1. 程式人生 > 實用技巧 >luogu P1283 【平板塗色】

luogu P1283 【平板塗色】

閒話

第一道完全靠自己想出的藍題,怎麼說也要寫篇題解紀念一下

思路

看完題面,使用DFS應該是很顯然了

但是不同於普通深搜的列舉,這道題有一個限制條件

那就是一個矩形只能在所有緊靠它上方的矩形塗色後,才能塗色

所以我在開始搜尋前做了預處理,處理出了每個矩形在塗色前有哪些矩形需要先塗好,搜尋時再去判斷

每個需要預塗的矩形是否已先塗好

另外,由於搜尋時我是一次性將所有可以塗色的塗完,所以需要先對所有矩形按照從上到下的順序進行排序,這樣就可以保證在一次性的塗色中,當我要塗下方的矩形時,上方的同顏色矩形已經塗完了

之後的事情就非常簡單,只要照著DFS的模板打就行了

沒有剪枝好像由於資料範圍過小水過了

AC程式碼如下(帶很詳細的註釋)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int n,minn=1e9,tot,sum[17],ss[17][17],ans[1000],v;sum[i]代表第i個矩形上方緊靠著的矩形數
struct node{              //ss[i][j]代表第i個矩形的第j個緊靠著的矩形是哪一個 
	int x1,y1,x2,y2;
	int d;
}s[17];//s[i].x1和y1代表第i個矩形左上方點的座標,s[i].x2和y2代表右下方點的座標,s[i].d代表要塗的顏色 
bool ex[17];
void dfs(int k,int su)//k為拿起刷子的次數,su為已經塗色的矩形數目 
{
	if(su==n)
	{
		minn=min(minn,k);
		return;
	}
	for(int g=1;g<=tot;g++)//tot為顏色總數
	{
		int f=su,lin[17],ff=0;//lin[i]為臨時陣列,用來記錄新塗了哪些矩形,方便之後回溯 
		for(int i=1;i<=16;i++)lin[i]=0; 
		for(int i=1;i<=n;i++)
		{
			if(s[i].d==g&&ex[i]==0)
			{
				int si=0;
				for(int j=1;j<=sum[i];j++)//判斷需要的矩形有幾個已經預先塗好 
				if(ex[ss[i][j]])si++;
				if(si==sum[i])//如果都塗好了就說明可以塗這個矩形了 
				{
					ex[i]=1;lin[++ff]=i;//標記為已塗過 
					su++;
				}
			}
		}
		if(f==su)continue;//如果用這個顏色不能塗更多矩形,就換一個顏色 
		ans[++v]=g;//記錄每一次使用的顏色 
		if(ans[v-1]!=ans[v]&&v!=1)//如果與上一次使用的顏色不同,就將次數加1 
		dfs(k+1,su);
		if(ans[v-1]==ans[v]||v==1)//如果與上一次使用的顏色相同或者是第一次使用,就不加次數 
		dfs(k,su);
		ans[v]=0;--v;//回溯 
		for(int i=1;i<=ff;i++)
		ex[lin[i]]=0,su--;
	}
}
bool cmp(node a,node b)
{
	if(a.x1==b.x1)return a.y1<b.y1;
	return a.x1<b.x1;
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>s[i].x1>>s[i].y1>>s[i].x2>>s[i].y2>>s[i].d;
		tot=max(tot,s[i].d);//更新tot 
	}
	sort(s+1,s+n+1,cmp);//從上到下排序 
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
	{
		if(i!=j)
		{    //如果其他矩形的y1與y2有一個在此矩形的y1與y2之間,並且是緊靠著的,就是合法的 
			if(((s[j].y1>=s[i].y1&&s[j].y1<s[i].y2)||(s[j].y2>s[i].y1&&s[j].y2<=s[i].y2))&&s[j].x1<s[i].x1&&s[i].x1==s[j].x2)
			{
				sum[i]++;//個數加1 
				ss[i][sum[i]]=j;//記錄是哪個矩形 
			}
		}
	}
	dfs(1,0);
	printf("%d",minn);
	return 0;
}

第一次寫題解,如有不妥之處還請海涵