#include <bits/stdc++.h>
using namespace std;
/*
重点:
剪枝:当前剩余的的总块数的一半要大于任意颜色的剩余数目
否则无论如何会相邻
*/
int N, M, K;
int chessboard[10][10] = { 0 };//颜色棋盘 记录颜色
int color[36];//每种颜色需要数量
//检查当前颜色是否可以放置
bool checked(int color, int x, int y) {
// 检查左边是否同色
if (y > 0 && chessboard[x][y - 1] == color)
return false;
// 检查上边是否同色
if (x > 0 && chessboard[x - 1][y] == color)
return false;
return true;
}
//由左到右 由上到下 进行dfs
bool DFS(int x, int y) {
//已经找到一种正确答案 说明到头了
if (x == N)
return true;
//剪枝
int res = N * M - x * M - y + 1;
//遍历每一种颜色剩余数量
for (int i = 0; i < K; i++) {
if (color[i] > res / 2)
return false;
}
//向下dfs 尝试每一种颜色
for (int i = 0; i < K; i++) {
if (color[i] && checked(i, x, y)) {
color[i]--;
chessboard[x][y] = i;//涂色
int nx = (y == M - 1) ? x + 1 : x;
int ny = (y == M - 1) ? 0 : y + 1;
if (DFS(nx, ny)) return true; // 递归调用
//会到这里 说明都失败了
//回溯
chessboard[x][y] = 0;
color[i]++;
}
}
return false;
}
int main() {
int T;
cin >> T;
for (int i = 1; i <= T; i++) {
//初始化
cin >> N >> M >> K;//N*M矩阵 涂K种颜色
memset(color, 0, sizeof(color));
memset(chessboard, 0, sizeof(chessboard));
for (int i = 0; i < K; i++) {
cin >> color[i];//每种颜色图多少个块
}
//DFS寻找答案
cout << "Case #" << i << ":" << endl;
if (DFS(0, 0)) {
cout << "YES" << endl;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
cout << chessboard[i][j] + 1 << " ";
}
cout << endl;
}
}
else {
cout << "NO" << endl;
}
}
return 0;
}
这道题是借鉴大佬代码 自己复现的
DFS+剪枝:
关键在于剪枝:
int res = N * M - x * M - y + 1;
//遍历每一种颜色剩余数量
for (int i = 0; i < K; i++) {
if (color[i] > res / 2)
return false;
}
不知道为什么少个+1就wa了
然后就是套dfs模板+回溯
dfs按照从左到右 从上到下顺序 所以只有两个方向
注意checked数组不要越界
因为只需要一种情况所以当找到的时候 直接return true;一直返回到主函数 当前chessboard保留的即是正确答案。
复现出来还是很有成就感的