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;
}

第一次写题解,如有不妥之处还请海涵

原文地址:https://www.cnblogs.com/luotao0034/p/14063174.html