题目大意:
给你一个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 ",ans); 50 return 0; 51 }