题目
求用1*2的牌铺满n*m大小的棋盘的方案数。
思路
关键是设计牌状态,尤其是竖着的。
如果令竖着的骨牌上面为1。
这样两个状态不冲突的条件是某一位不能同时为1且或运算后不能有连续奇数个0。
最终第n行应该是全0。
考虑第一行, 只要其不含奇数个0, 就合法,为了方便, 设计第0行的0方案数为1, 这样按照策略转移第一行的全部合法状态都会变成1. 当然也可以特殊处理第一行。
最终答案为f[n][0];
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
int n, m;
long long f[12][1<<11];
int valid[1<<11];
int check(int S) {
int k = 0;
while(k < m) {
if(S&1) S >>= 1, k++;
else if(!(S&1) && !(S&2) && k+2 <= m) S >>= 2, k += 2;
else return 1;
}
return 0;
}
int main() {
while(scanf("%d%d", &n, &m) && n && m) {
memset(f, 0, sizeof(f));
memset(valid, 0, sizeof(valid));
for(int S = 0; S < (1<<m); S++) {
if(check(S)) continue;
valid[S] = 1;
}
//We can also deal the first line and start at i = 2
// for(int S = 0; S < (1<<m); S++) {
// if(check(S)) continue;
// valid[S] = 1;
// f[1][S] = 1;
// }
f[0][0] = 1;
int now = 1;
for(int i = 1; i <= n; i++, now ^= 1) {
memset(f[now], 0, sizeof(f[now]));
for(int v = 0; v < (1<<m); v++) {
for(int u = 0; u < (1<<m); u++) {
if((u&v) || !valid[u|v]) continue;
f[now][v] += f[now^1][u];
}
}
}
cout << f[now^1][0] << '
';
}
return 0;
}
如果令竖着的骨牌下面为1. 状态冲突条件不变。
考虑第一行只能全为0, 设计其方案数为1. 这样第二行合法的便全部可以转移呈1.
处理完后, 最后一行需要遍历一下所有状态, 只要不含奇数个0, 就合法,累加到答案中。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
int n, m;
long long f[12][1<<11];
int valid[1<<11];
int check(int S) {
int k = 0;
while(k < m) {
if(S&1) S >>= 1, k++;
else if(!(S&1) && !(S&2) && k+2 <= m) S >>= 2, k += 2;
else return 1;
}
return 0;
}
int main() {
while(scanf("%d%d", &n, &m) && n && m) {
memset(f, 0, sizeof(f));
memset(valid, 0, sizeof(valid));
for(int S = 0; S < (1<<m); S++) {
if(check(S)) continue;
valid[S] = 1;
}
f[1][0] = 1;
int now = 0;
for(int i = 2; i <= n; i++, now ^= 1) {
memset(f[now], 0, sizeof(f[now]));
for(int v = 0; v < (1<<m); v++) {
for(int u = 0; u < (1<<m); u++) {
if((u&v) || !valid[u|v]) continue;
f[now][v] += f[now^1][u];
}
}
}
long long ans = 0;
for(int S = 0; S < (1<<m); S++) if(valid[S]) ans += f[now^1][S];
cout << ans << '
';
}
return 0;
}
关键
竖着的骨牌的处理不同, 决策不同。
动态规划状态的设计和转移的策略。 需要考虑完备。
预处理合法状态。