题意:给定n*m格子,每个格子被染成了黑色或者白色,现在要用1*2的砖块覆盖这些格子,块与块不得重叠,且覆盖所有的白色格子,但不覆盖任意一个黑色格子,求一共有多少种覆盖方法。
思路:书上给的思路太巧妙以至于一时无法参透,于是找了一些相关的铺砖问题的解法,在此思路上改进了一下。具体思路可以参考https://blog.csdn.net/Lu597203933/article/details/44137277
这个问题在此基础上多了一个条件,即黑色格子无法被覆盖,略作改进即可。
实现代码:
#define _CRT_SECURE_NO_DEPRECATE #include <iostream> #include<vector> #include<algorithm> using namespace std; #define N_MAX 16 #define MOD 10000000 #define INF 0x3f3f3f3f int n, m; char color[N_MAX][N_MAX]; int dp[N_MAX][1 << N_MAX]; bool TestFirstLine(int k) {//测试状态k是否可以作为第一列 int i = 0; while (i<m) { if (color[0][i] == 'x') { if ((k >> i) & 1)i++; else return false; } else { if (!(k >> i & 1))i++; else if (i == m - 1 || !(k >> (i + 1) & 1))return false; else i += 2; } } return true; } bool judge(int k, int j) {//第j行状态k是否合法,即状态k在规定黑色的格子处必须是1,否则不合法 int i = 0; while (i<m) { if (!(k >> i & 1) && color[j][i] == 'x')return false; i++; } return true; } bool Testcompatible(int cur, int prev, int k) {//cur是当前状态,prev是上一次的状态 if (!judge(prev, k - 1))return false; int i = 0; while (i<m) { if (!(cur >> i & 1)) { if ((prev >> i & 1)) i++; else return false; } else if (color[k][i] == 'x') { if (prev >> i & 1)i++; else return false; } else { if (!(prev >> i & 1))i++; else { if (i == m - 1 ||!((cur>>(i+1)&1)&&(prev >> (i + 1))&1))return false;//!!!!! else i += 2; } } } return true; } int main() { while (cin >> n >> m) { for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) scanf(" %c", &color[i][j]); if (m > n)swap(m, n); memset(dp, 0, sizeof(dp)); int allstates = 1 << m; for (int j = 0; j < allstates; j++) { if (TestFirstLine(j))dp[0][j] = 1; } for (int i = 1; i < n; i++) { for (int j = 0; j < allstates; j++) { for (int k = 0; k < allstates; k++) { if (!judge(j, i))continue; if (Testcompatible(j, k, i)) { dp[i][j] += dp[i - 1][k]; dp[i][j] %= MOD; } } } } cout << dp[n - 1][allstates - 1] << endl; } return 0; } /*(.是白色,*是黑色) 3 3 . . . . x . . . . output:2 */