搜索题,不好好写会超时的搜索题


其实如果归类到搜索,弱觉得不是特别恰当。搜索只是为了得到某一个可行解,本质上的思路是数学上的想法和构造的解法

http://acm.hdu.edu.cn/showproblem.php?pid=5113


看到Special Judge想到多解的深搜是很正常的,有没有想过去构造合法解呢?

题意:n*m的矩阵,k种颜色,每种颜色a【i】个,问是否有方案,使得n*m的矩阵中,每个格子涂上与周围四个不相同的颜色,而且恰好把颜色使用完?


由于n和m都很小,考虑到简单的深搜是肯定没有问题的?

那么如何搜?先看个超时代码:戳我看超时代码


为什么会超时呢?因为深搜退完再进的情况可能出现了很多次

避免超时,只需要一句话:sort!


对各种颜色按照从大到小的方式排序,一个是避免超时,一个是从构造性的原理来解释:

只要最多的颜色数量不超过总数量即n*m的一半,那么是肯定有解的


最特殊的情况无非是这种:
4 4 2
8 8
即4*4的矩阵中16个格子,两种颜***r> 所以相互间隔开来就好
1 2 1 2
2 1 2 1
1 2 1 2
2 1 2 1
相当于构造一个矩阵,相邻数字均不相同
充要条件就是最多的颜色数量不超过总数量即n*m的一半


可以比较,AC代码与TLE代码差别非常小,但是数学和构造的思想在代码中无法体现,只能体现在思维中


int t,n,m,k;
struct node{
	int num,pos;
}data[30];
int mp[10][10];

void Print(){
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
		printf("%d%c",mp[i][j],j==m?'\n':' ');
}

bool dfs(int x,int y){
	if (x==n+1) return true;
	for(int i=1;i<=k;i++)//选择哪一种颜色
		if (data[i].num){
			if (mp[x-1][y]!=data[i].pos&&mp[x][y-1]!=data[i].pos){
				//为什么这儿不需要考虑出矩形
				//因为外围有一圈以0作为边界的墙
				//从左往右,从上往下涂色即可
				data[i].num--;
				mp[x][y]=data[i].pos;
				if (y+1<=m){
					if (dfs(x,y+1)) return true;
				}
				else if (dfs(x+1,1)) return true;
				data[i].num++;
			}
		}
	return false;
}

int cmp(node a,node b){
	if (a.num!=b.num) return a.num>b.num;
	return a.pos<b.pos;
}

int main(){
	//input;
	scanf("%d",&t);
	for(int Case=1;Case<=t;Case++){
		scanf("%d%d%d",&n,&m,&k);
		for(int i=1;i<=k;i++){
			scanf("%d",&data[i].num);
			data[i].pos=i;
		}
		sort(data+1,data+k+1,cmp);
		//为啥要排序?
		//排序一个是为了不超时,一个是为了得到最多的颜色值 
		printf("Case #%d:\n",Case);
		//脑洞题:
		//如果最多的颜色不超过一半
		//那么选一个最多的,选一个其他的,全部隔开就好了
		//所以这个题并不是个搜索
		//是个数学上的构造 
		if (data[1].num>(m*n+1)/2){
			cout<<"NO"<<endl;
			continue;
		}
		cout<<"YES"<<endl;
		dfs(1,1);
		Print();
	}
	return 0;
}