poj 3254 状压dp
题意:给出一个n行m列的草地,1表示肥沃,0表示贫瘠,现在要把一些牛放在肥沃的草地上,但是要求所有牛不能相邻,问你有多少种放法。
链接:点我
定义状态dp【i】【j】,第 i 行状态为 j 的时候放牛的种数。
去年暑假做过的题,现在忘光了
1 #include <cstdio> 2 #include <cstring> 3 const int N = 13; 4 const int M = 1<<N; 5 const int mod = 100000000; 6 int st[M],map[M]; //分别存每一行的状态和给出地的状态 7 int dp[N][M]; //表示在第i行状态为j时候可以放牛的种数 8 bool judge1(int x) //判断二进制有没有相邻的1 9 { 10 return (x&(x<<1)); 11 } 12 bool judge2(int i,int x) 13 { 14 return (map[i]&st[x]); 15 } 16 int main() 17 { 18 int n,m,x; 19 while(~scanf("%d%d",&n,&m)) 20 { 21 memset(st,0,sizeof(st)); 22 memset(map,0,sizeof(map)); 23 memset(dp,0,sizeof(dp)); 24 for(int i=1;i<=n;i++) 25 { 26 for(int j=1;j<=m;j++){ 27 scanf("%d",&x); 28 if(x==0) 29 map[i]+=(1<<(j-1)); 30 } 31 32 } 33 int k=0; 34 for(int i=0;i<(1<<m);i++){ 35 if(!judge1(i)) 36 st[k++]=i; 37 } 38 for(int i=0;i<k;i++) 39 { 40 if(!judge2(1,i)) 41 dp[1][i]=1; 42 } 43 for(int i=2;i<=n;i++) 44 { 45 for(int j=0;j<k;j++) 46 { 47 if(judge2(i,j)) //判断第i行 假如按状态j放牛的话行不行。 48 continue; 49 for(int f=0;f<k;f++) //上一行的状态 50 { 51 if(judge2(i-1,f)) //剪枝 判断上一行与其状态是否满足 52 continue; 53 if(!(st[j]&st[f])) 54 dp[i][j]+=dp[i-1][f]; 55 } 56 } 57 } 58 int ans=0; 59 for(int i=0;i<k;i++){ 60 ans+=dp[n][i]; 61 ans%=mod; 62 } 63 printf("%d\n",ans); 64 } 65 return 0; 66 }