思路:状态压缩dp,用二进制位的1表示放了,0表示没有放。设dp[i][j],表示第i行状态为j时,前i行的方案数,状态转移方程就是 dp[i][j] += dp[i-1][k],j与k这两个状态不冲突。最后答案就是dp[n][1...top] 之和。
#include<cstdio> #include<string> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int MAXN = 15; const int MOD = 100000000; int dp[MAXN][400]; int top, tmp, n, m; int map[MAXN], status[400]; void init(){ top = 1; int up = 1 << m; memset(dp, 0, sizeof(dp)); memset(map, 0, sizeof(map)); for(int i = 0;i < up;i ++){ if(i & (i << 1)) continue; status[top++] = i; } } int main(){ //freopen("in.c", "r", stdin); while(~scanf("%d%d", &n, &m)){ init(); for(int i = 1;i <= n;i ++){ for(int j = 0;j < m;j ++){ scanf("%d", &tmp); if(!tmp) map[i] |= (1 << j); } } for(int i = 1;i < top;i ++){ if(map[1] & status[i]) continue; dp[1][i] = 1; } for(int i = 2;i <= n;i ++){ for(int j = 1;j < top;j ++){ if(map[i] & status[j]) continue; for(int k = 1;k < top;k ++){ if(status[j] & status[k] || map[i-1] & status[k]) continue; dp[i][j] += dp[i-1][k]; dp[i][j] %= MOD; } } } int ans = 0; for(int i = 1;i < top;i ++){ ans += dp[n][i]; ans %= MOD; } printf("%d ", ans); } return 0; }