poj - 3254 Corn Fields (状态压缩dp入门)

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 }

 

转载于:https://www.cnblogs.com/nowandforever/p/4713997.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值