1. 程式人生 > >[USACO06NOV]Corn Fields

[USACO06NOV]Corn Fields

main pri return for cor code lds amp next

題目大意:
  給你一個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 }

[USACO06NOV]Corn Fields