题解【P1817 棋盘染色】
OIer 必备技能——打表。
闲话少说,切入正题——
其实这道题一开始想到了状压,但是看到
这是打表代码:
#include <iostream>
#include <cstring>
#define MAXN 100000
#define int long long
using namespace std;
int M[10][10], n, m, ans = 0;
int dx[5] = {0, 1, -1, 0, 0};
int dy[5] = {0, 0, 0, 1, -1};
void dfs(int x, int y) {
//我觉得唯一要扯的地方就是为什么是 (x >= n) 和 (y >= m) 而不是大于
//因为如果是大于的话,那么就可能会出现有一条黑色横杠从第 1 列到 m 列导致白色部分变成两个连通块
//或者说有一条黑色棍子从第 1 行到第 n 行导致白色部分变成两个连通块
if(x < 1 || x >= n || y < 1 || y >= m) {
ans++;
return ;
}
for(int p = 1; p <= 4; p++) {
M[x][y] = 1;
int xx = x + dx[p], yy = y + dy[p];
if(!M[xx][yy]) dfs(xx, yy);
M[x][y] = 0;
}
}
signed main() {
freopen("if-else.txt", "w", stdout);
for(n = 1; n <= 7; n++)
for(m = 1; m <= 8; m++) {
ans = 0;
for(int p = 1; p < n; p++) {
memset(M, 0, sizeof(M));
M[p][0] = 1;
dfs(p, 1);
}
for(int p = 1; p < m; p++) {
memset(M, 0, sizeof(M));
M[0][p] = 1;
dfs(1, p);
}
cout << "else if(n == " << n << " && m == " << m << ")" << " cout << " << ans * 2 << endl;
//为什么要 * 2?因为把黑白颠倒也是一种方案,上面的 dfs 没有统计这种方案
}
}
然后根据这个打表代码并且对结果略微修建,我们就能得到
if(n == 1 && m == 1) cout << "0" << endl;
else if(n == 1 && m == 2) cout << "2" << endl;
else if(n == 1 && m == 3) cout << "4" << endl;
else if(n == 1 && m == 4) cout << "6" << endl;
else if(n == 1 && m == 5) cout << "8" << endl;
else if(n == 1 && m == 6) cout << "10" << endl;
else if(n == 1 && m == 7) cout << "12" << endl;
else if(n == 1 && m == 8) cout << "14" << endl;
else if(n == 2 && m == 1) cout << "2" << endl;
else if(n == 2 && m == 2) cout << "12" << endl;
else if(n == 2 && m == 3) cout << "30" << endl;
else if(n == 2 && m == 4) cout << "56" << endl;
else if(n == 2 && m == 5) cout << "90" << endl;
else if(n == 2 && m == 6) cout << "132" << endl;
else if(n == 2 && m == 7) cout << "182" << endl;
else if(n == 2 && m == 8) cout << "240" << endl;
else if(n == 3 && m == 1) cout << "4" << endl;
else if(n == 3 && m == 2) cout << "30" << endl;
else if(n == 3 && m == 3) cout << "104" << endl;
else if(n == 3 && m == 4) cout << "286" << endl;
else if(n == 3 && m == 5) cout << "700" << endl;
else if(n == 3 && m == 6) cout << "1598" << endl;
else if(n == 3 && m == 7) cout << "3488" << endl;
else if(n == 3 && m == 8) cout << "7390" << endl;
else if(n == 4 && m == 1) cout << "6" << endl;
else if(n == 4 && m == 2) cout << "56" << endl;
else if(n == 4 && m == 3) cout << "286" << endl;
else if(n == 4 && m == 4) cout << "1228" << endl;
else if(n == 4 && m == 5) cout << "4862" << endl;
else if(n == 4 && m == 6) cout << "18368" << endl;
else if(n == 4 && m == 7) cout << "67206" << endl;
else if(n == 4 && m == 8) cout << "240180" << endl;
else if(n == 5 && m == 1) cout << "8" << endl;
else if(n == 5 && m == 2) cout << "90" << endl;
else if(n == 5 && m == 3) cout << "700" << endl;
else if(n == 5 && m == 4) cout << "4862" << endl;
else if(n == 5 && m == 5) cout << "32000" << endl;
else if(n == 5 && m == 6) cout << "204294" << endl;
else if(n == 5 && m == 7) cout << "1274660" << endl;
else if(n == 5 && m == 8) cout << "7807790" << endl;
else if(n == 6 && m == 1) cout << "10" << endl;
else if(n == 6 && m == 2) cout << "132" << endl;
else if(n == 6 && m == 3) cout << "1598" << endl;
else if(n == 6 && m == 4) cout << "18368" << endl;
else if(n == 6 && m == 5) cout << "204294" << endl;
else if(n == 6 && m == 6) cout << "2228788" << endl;
else if(n == 6 && m == 7) cout << "23896710" << endl;
else if(n == 6 && m == 8) cout << "252488208" << endl;
else if(n == 7 && m == 1) cout << "12" << endl;
else if(n == 7 && m == 2) cout << "182" << endl;
else if(n == 7 && m == 3) cout << "3488" << endl;
else if(n == 7 && m == 4) cout << "67206" << endl;
else if(n == 7 && m == 5) cout << "1274660" << endl;
else if(n == 7 && m == 6) cout << "23896710" << endl;
else if(n == 7 && m == 7) cout << "441524056" << endl;
else if(n == 7 && m == 8) cout << "8056291934" << endl;
这样一张宏伟的大表啦~
事实证明,对于这样的数据范围很小的题目,可以暴力打表然后挂机个五六分钟,就能得到答案,比如说往年的这道棋盘问题。