http://poj.org/problem?id=3254
参考:http://blog.csdn.net/accry/article/details/6607703
农夫想在m*n的土地上种玉米,但是有的土地很贫瘠,所以不能种,每块土地标为1的表示能种,标为0的表示不能种,并且种玉米的土地不能相邻,
问有多少种合法的种植方案.(全部不种也算一种)
第一道状压,理解了比较久的时间.
就是用二进制的0和1代表土地种还是不种,这样每一行都可以用一个2进制数表示,列数<=12,故最多有2<<12种状态.
代表一个状态,就可以建立状态转移方程.dp[i][j]代表第i行状态为j时总的方案数,dp[i][j]=sigma(dp[i-1][j']);
判断冲突充分利用了位运算的性质,比如某个状态是否有相邻的1存在则状态x&(x>>1) 或者x&(x<<1)即可.因为等于向左或向右移动一位.
判断是否跟上一行的冲突也是一样.
用滚动数组总是写的不对,好像是初始化的问题.
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <vector> 5 #include <cstring> 6 #include <string> 7 #include <algorithm> 8 #include <string> 9 #include <set> 10 #include <functional> 11 #include <numeric> 12 #include <sstream> 13 #include <stack> 14 //#include <map> 15 #include <queue> 16 #include <deque> 17 //#pragma comment(linker, "/STACK:102400000,102400000") 18 #define CL(arr, val) memset(arr, val, sizeof(arr)) 19 20 #define ll long long 21 #define INF 0x7f7f7f7f 22 #define lc l,m,rt<<1 23 #define rc m + 1,r,rt<<1|1 24 #define pi acos(-1.0) 25 26 #define L(x) (x) << 1 27 #define R(x) (x) << 1 | 1 28 #define MID(l, r) (l + r) >> 1 29 #define Min(x, y) (x) < (y) ? (x) : (y) 30 #define Max(x, y) (x) < (y) ? (y) : (x) 31 #define E(x) (1 << (x)) 32 #define iabs(x) (x) < 0 ? -(x) : (x) 33 #define OUT(x) printf("%I64d\n", x) 34 #define lowbit(x) (x)&(-x) 35 #define Read() freopen("a.txt", "r", stdin) 36 #define Write() freopen("b.txt", "w", stdout); 37 #define maxn 110 38 #define maxv 5010 39 #define mod 1000000000 40 using namespace std; 41 int n,m,top=0; 42 int state[600],num[110]; 43 int dp[20][600]; //最多是600个状态,不知道是以什么方式算出来的 44 int cur[20]; 45 inline bool ok(int x) //判断同一行是否有相邻的1 46 { 47 if(x&x<<1) return 0; 48 return 1; 49 } 50 void init() //初始化 2^m个状态,把有相邻1的状态的去掉 51 { 52 top=0; 53 int total=1<<m; 54 for(int i=0;i<total;i++) 55 if(ok(i)) state[++top]=i; 56 } 57 inline bool fit(int x,int k) //判断状态x和读入的第k行是否冲突,注意cur[k]中1代表不能种, 58 { //所以只要相与为1则表示不行 59 if(x&cur[k]) return 0; 60 return 1; 61 } 62 int main() 63 { 64 //Read(); 65 while(~scanf("%d%d",&n,&m)) 66 { 67 init(); 68 memset(dp,0,sizeof(dp)); 69 for(int i=1;i<=n;i++) 70 { 71 cur[i]=0; 72 int num; 73 for(int j=1;j<=m;j++) //这里是为0表示可以种,为1表示是不可以种 74 { //注意和上面区分,这里主要是为了判断冲突. 75 scanf("%d",&num); 76 if(!num) cur[i]+=(1<<(m-j));//把每一行转换成2进制,并用cur存储 77 } 78 //printf("%d\n",cur[i]); 79 } 80 for(int i=1;i<=top;i++) //初始化第一行, 81 { 82 if(fit(state[i],1)) //不冲突表示可以放 83 dp[1][i]=1; 84 } 85 for(int i=2;i<=n;i++) 86 { 87 for(int j=1;j<=top;j++) 88 { 89 if(!fit(state[j],i)) continue; //判断第i行和读入的图是否冲突 90 for(int k=1;k<=top;k++) 91 { 92 if(!fit(state[k],i-1)) continue; //判断第i-1行是否冲突 93 if(state[j]&state[k]) continue;//判断第i行和第i-1行是否冲突 94 dp[i][j]=(dp[i][j]+dp[i-1][k])%mod; 95 } 96 } 97 } 98 int ans=0; 99 for(int i=1;i<=top;i++) 100 { 101 ans=(ans+dp[n][i])%mod; 102 } 103 printf("%d\n",ans); 104 } 105 return 0; 106 }