poj - 3254 Corn Fields (状态压缩dp入门)
2015-08-08 21:52
176 查看
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)即可.因为等于向左或向右移动一位.
判断是否跟上一行的冲突也是一样.
用滚动数组总是写的不对,好像是初始化的问题.
参考: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)即可.因为等于向左或向右移动一位.
判断是否跟上一行的冲突也是一样.
用滚动数组总是写的不对,好像是初始化的问题.
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <string> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> //#include <map> #include <queue> #include <deque> //#pragma comment(linker, "/STACK:102400000,102400000") #define CL(arr, val) memset(arr, val, sizeof(arr)) #define ll long long #define INF 0x7f7f7f7f #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define Read() freopen("a.txt", "r", stdin) #define Write() freopen("b.txt", "w", stdout); #define maxn 110 #define maxv 5010 #define mod 1000000000 using namespace std; int n,m,top=0; int state[600],num[110]; int dp[20][600]; //最多是600个状态,不知道是以什么方式算出来的 int cur[20]; inline bool ok(int x) //判断同一行是否有相邻的1 { if(x&x<<1) return 0; return 1; } void init() //初始化 2^m个状态,把有相邻1的状态的去掉 { top=0; int total=1<<m; for(int i=0;i<total;i++) if(ok(i)) state[++top]=i; } inline bool fit(int x,int k) //判断状态x和读入的第k行是否冲突,注意cur[k]中1代表不能种, { //所以只要相与为1则表示不行 if(x&cur[k]) return 0; return 1; } int main() { //Read(); while(~scanf("%d%d",&n,&m)) { init(); memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++) { cur[i]=0; int num; for(int j=1;j<=m;j++) //这里是为0表示可以种,为1表示是不可以种 { //注意和上面区分,这里主要是为了判断冲突. scanf("%d",&num); if(!num) cur[i]+=(1<<(m-j));//把每一行转换成2进制,并用cur存储 } //printf("%d\n",cur[i]); } for(int i=1;i<=top;i++) //初始化第一行, { if(fit(state[i],1)) //不冲突表示可以放 dp[1][i]=1; } for(int i=2;i<=n;i++) { for(int j=1;j<=top;j++) { if(!fit(state[j],i)) continue; //判断第i行和读入的图是否冲突 for(int k=1;k<=top;k++) { if(!fit(state[k],i-1)) continue; //判断第i-1行是否冲突 if(state[j]&state[k]) continue;//判断第i行和第i-1行是否冲突 dp[i][j]=(dp[i][j]+dp[i-1][k])%mod; } } } int ans=0; for(int i=1;i<=top;i++) { ans=(ans+dp [i])%mod; } printf("%d\n",ans); } return 0; }
相关文章推荐
- 条款16:成对使用new和delete时,采取相同的形式
- Codeforces Gym 100286J Javanese Cryptoanalysis 傻逼暴力
- 杭电OJ 1002 大数相加
- 代理模式
- Hive客户端多并发问题解决方法记录
- HDOJ 5353 Average 模拟
- [POJ 2444] Partition a Matrix 暴力
- selection sort(选择排序)
- 当 MUST_CHANGE 为 ON (开)时,不能将 CHECK_POLICY 和 CHECK_EXPIRATION 选项设为 OFF (关)
- Android--编程方法之外的常识
- Android中的ViewPager和 PagerAdapter的初步理解和使用
- Installing Tomcat 8 on OS X 10.10 Yosemite
- fwrite()函数和fread()函数
- Linux多线程【转载】
- codeforces Gym 100286H Hell on the Markets
- or1200于IMMU分析
- 贪心算法之Entropy
- 01 贪吃蛇
- Android View(一)
- The mook jong