[USACO06NOV]Corn Fields

题目大意:
  给你一个m*n的01矩阵,请你搞一些破坏。
  你可以选择搞坏任意一个数字为1的格子。
  如果格子上的数字为0,它本来就是坏的,不用管它。
  为了掩人耳目,你搞坏的格子不能直接相邻(即不能有公共边),不包括原来就坏掉的格子。
  问有多少种搞破坏的方案。

思路:
  状压DP。
  f[i][j]表示第i行状态为j的方案数。
  我们可以枚举当前行的状态j和上一行的状态k,并判断是否合法。
  简单来说就是判断状态中是否有相邻的格子,是否有和上一行重复的,是否有本来就坏掉的格子。
  然后直接暴力转移即可。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<cstring>
 4 #include<algorithm>
 5 inline int getint() {
 6     register char ch;
 7     while(!isdigit(ch=getchar()));
 8     register int x=ch^'0';
 9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
10     return x;
11 }
12 const int mod=1e8,inf=0x7fffffff;
13 const int M=12;
14 int a[2];
15 int f[2][1<<M];
16 int main() {
17     const int m=getint(),n=getint();
18     for(register int i=0;i<m;i++) {
19         a[i&1]=0;
20         memset(f[i&1],0,sizeof *f);
21         for(register int j=0;j<n;j++) {
22             if(getint()) a[i&1]|=1<<j;
23         }
24         for(register int j=0;j<(1<<n);j++) {
25             for(register int t=1;t<n;t++) {
26                 if((j&(1<<t))&&(j&(1<<(t-1)))) goto Next_j;
27             }
28             if((a[i&1]|j)!=a[i&1]) continue;
29             if(!i) {
30                 f[i&1][j]=1;
31                 continue;
32             }
33             for(register int k=0;k<(1<<n);k++) {
34                 for(register int t=1;t<n;t++) {
35                     if((k&(1<<t))&&(k&(1<<(t-1)))) goto Next_k;
36                 }
37                 if((a[!(i&1)]|k)!=a[!(i&1)]) continue;
38                 if(j&k) continue;
39                 f[i&1][j]=(f[i&1][j]+f[!(i&1)][k])%mod;
40                 Next_k:;
41             }
42             Next_j:;
43         }
44     }
45     int ans=0;
46     for(register int i=0;i<(1<<n);i++) {
47         ans=(ans+f[!(m&1)][i])%mod;
48     }
49     printf("%d\n",ans);
50     return 0;
51 }

 

posted @ 2017-10-27 13:12  skylee03  阅读(98)  评论(0编辑  收藏  举报