残缺棋盘--状压DP

P1:给你一个n*m的残缺棋盘(部分位置不可放棋子),求棋子两两不能相邻的方案数mod987654321

分析:这里相邻理解为四联通,我们将每一行看作一个状态,用上一行来推下一行的方案数。

代码:

 1 #include "bits/stdc++.h"
 2 
 3 #define ll long long
 4 #define maxn 10
 5 #define maxm 10005
 6 using namespace std;
 7 
 8 int n, m, N, tot, s[maxm]; //s[i]表示第i种可行状态
 9 ll ans, f[maxn][maxm];    //f[i][j][l]表示第i行状态为第j种摆放的方案数
10 int a[20][20];
11 
12 bool check(int id, int x) {
13     for (int j = m; j >= 1; j--) {
14         int y = x & 1;
15         if (y == 1 && a[id][j] == 0)
16             return 0;
17         x >>= 1;
18     }
19     return 1;
20 }
21 int main() {
22     cin >> n >> m;
23     for (int i = 1; i <= n; i++)
24         for (int j = 1; j <= m; j++) cin >> a[i][j];
25 
26     N = 1 << m;
27     memset(f, 0, sizeof(f));
28     for (int i = 0; i < N; ++i) {
29         if (i & (i << 1))continue;
30         s[++tot] = i;
31         if (!check(1, s[tot])) continue;
32         f[1][tot] = 1;    //第一行需要单独初始化
33     }
34     for (int i = 2; i <= n; ++i)
35         for (int j = 1; j <= tot; ++j) {
36             if (!check(i, s[j])) continue;
37             for (int k = 1; k <= tot; ++k) {
38                 if (s[j] & s[k])continue;
39                 f[i][j] += f[i - 1][k];
40             }
41         }
42     for (int i = 1; i <= tot; ++i) ans += f[n][i];
43     printf("%lld", ans);
44     return 0;
45 }

 

八联通的做法与之类似,改一下判断相邻条件即可。

 

posted @ 2019-05-22 21:46  thges  阅读(220)  评论(0编辑  收藏  举报