HDU - 5113 Black And White (DFS+技巧剪枝)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5113

看了看有的博客,看了hdu的discuss都是这样剪枝的…
即代码中的注释:当剩余的cell的一半(向上取整)小于某个颜色的剩余数,必有两个相邻cell颜色相同。
很好理解,因为颜色一定会用完,剩余的cell一半以上(不包括)会有同样的颜色。只看一种颜色的情况,在颜色不相邻的情况下,使得染色数目最多的方式就是两两染色的cell之间有一个空cell,如果为奇数,则染色数目为(n+1)/2,若为偶数则为n/2,这时如果该颜色还有剩余则必将填入间隔的空cell中,则必有相邻cell颜色相同。

大概这就是为什么说学算法要数学好吧,数学是最需要奇思妙想的科目了…

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int dir[4][2] = { {-1,0},{0,-1}, {1,0},{0,1} };
int color[30], a[10][10];
int T, N, M, K, kase = 0, ALL;
bool ok;

bool check(int row, int col) {
	if (row < 0 || row >= N || col < 0 || col >= M)return false;
	return true;
}

bool judge(int row, int col, int x) {
	for (int e = 0; e < 4; e++) {
		int row2 = row + dir[e][0];
		int col2 = col + dir[e][1];
		if (check(row2, col2)) {
			if (a[row2][col2] == x)return false;
		}
	}
	return true;
}
inline void dfs(int pos) {
	for (int i = 1; i <= K; i++) //当剩余的cell的一半(向上取整)小于某个颜色的剩余数,必有两个相邻cell颜色相同
		if ((ALL + 1 - pos) / 2 < color[i]) return;
	if (pos == ALL) {
		ok = true; return;
	}
	int row = pos / M;
	int col = pos % M;
	for (int i = 1; i <= K; i++) {
		if (!color[i])continue;
		if (judge(row,col,i)) {
			a[row][col] = i;
			color[i]--;
			dfs(pos + 1);
			if (!ok) {
				a[row][col] = 0; 
				color[i]++;
			}
			else return;
		}
	}
}

int main(void) {
	scanf("%d", &T);
	while (T--) {
		scanf("%d %d %d", &N, &M, &K);
		for (int i = 1; i <= K; i++)
			scanf("%d", &color[i]);
		ALL = N * M;
		ok = false;
		memset(a, 0, sizeof(a));	
		printf("Case #%d:\n", ++kase);
		dfs(0);
		if (!ok)printf("NO\n");
		else {
			printf("YES\n");
			for (int i = 0; i < N; i++) 
				for (int j = 0; j < M; j++)
					printf("%d%c", a[i][j], j == M - 1 ? '\n' : ' ');
		}
	}
	return 0;
}
发布了104 篇原创文章 · 获赞 97 · 访问量 4515

猜你喜欢

转载自blog.csdn.net/TK_wang_/article/details/105324481