poj3524 Corn Fields(状态压缩dp)
来源:互联网 发布:大数据涉及技术要求 编辑:程序博客网 时间:2024/05/16 09:12
前两天实验室没网,好好看了下状态压缩,现在编辑一下(2016/4/11)。
说真的,入门真的很难懂,难点有两个。位运算,dp关系的处理。
先说明什么是状态压缩:用一个数来表示一组数,以降低表示状态所需的维数的解题手段,就叫做状态压缩。 参考博客,真理get~
再声明各个数组的作用:
state[N],刚开始初始化状态,先对1左移宽度大小,然后从1开始记录每个状态。其中每个数字代表一个状态,存到state里。
cur[N],记录样例中每行的状态,如果是0,通过将1左移相应位置来代表0(注意1变0,0变1,这样方便求&),同样转化为十进制,存到cur里。
两个数组都弄好后,初始化dp第一行,通过对state[j]和cur[i]求&,找出2^n所有状态中对于当前状态可行(没有1是连续)的状态,将其初始化为1(一种方案)。
接下来的dp都是建立在第一行的基础上,数塔式递归。先遍历每行每列,然后由于要和前一状态比较(纵向判断),再遍历一次每列。为了判断是否可行加以剪枝,一种是该可能状态与当前行状态判断,不匹配即跳过。另一种是与上一行判断,不匹配即跳过。注意这里比较的是整行的状态,而不是单个状态。
最后把最后一行全加起来,即为总方案数(题中要求取模别忘了)。
然后是难点:
1、位运算。这里涉及到的位运算有两个,<<(左移)和&(与)。左移太简单不说,主要是&运算。
首先明白&运算的过程:4=0000 0000 0000 0100 &7 =0000 0000 0000 0111= 0000 0000 0000 0100。说白了就是变为二进制后相同位置同时为1才能为1,否则为0。看似简单,但是可以做到我们好多想象不到的事。
(1)、本题中x & (x << 1)可以判断是否有1相邻,若相邻则求的一个不为0的数,返回false(因为相邻,所以该种情况不可行)。
(2)、本题中x & y可以判断是否冲突。
一种是state[j]&cur[i],因为本题cur中1即是0,所以一旦求的一个不为0的数,返回false(这个地方不能放玉米)。
一种是state[j] & state[k],即为上下行状态的比较,若相同位置同为1(都放玉米),求的不为0的数,跳过循环。
2、dp关系的处理。
并不是所有的状态压缩都可以像本题一样数塔式递归,不同的题用不同的dp方法,例如炮兵阵地,切记。
觉得经典所以写了解释,但感觉写了这么多也只是入了个门吧,泪。
#include <stdio.h>#include <algorithm>#include <string.h>using namespace std;const int N = 4500;const int INF = 1e8;const int mod = 100000000;int n, m, top, total;int state[N], cur[20], dp[20][N];bool ok(int x){ if(x & (x << 1)) return false; else return true;}void init(){ top = 0; total = 1 << n; for(int i = 0; i < total; i ++) { if(ok(i)) state[++ top] = i; }}bool fit(int x, int y){ if(x & y) return false; else return true;}int main(){ // freopen("in.txt", "r", stdin); int num; while(~scanf("%d%d", &m, &n)) { memset(dp, 0, sizeof(dp)); init(); //输入,同时记录该行的状态 for(int i = 1; i <= m; i ++) { cur[i] = 0; for(int j = 1; j <= n; j ++) { scanf("%d", &num); if(num == 0) cur[i] += (1 << (n - j)); } } //初始化第一行 for(int i = 1; i <= top; i ++) { if(fit(state[i], cur[1])) dp[1][i] = 1; } //分层dp for(int i = 2; i <= m; i ++) { for(int j = 1; j <= top; j ++) { if(!fit(state[j], cur[i])) continue; for(int k = 1; k <= top; k ++) { if(!fit(state[k], cur[i - 1])) continue; if(state[j] & state[k]) continue; dp[i][j] = (dp[i][j] + dp[i - 1][k]) % mod; } } } //输出 int ans = 0; for(int i = 1; i <= top; i ++) ans = (ans + dp[m][i]) % mod; printf("%d\n", ans); }}
- poj3524 Corn Fields(状态压缩dp)
- poj3254 Corn Fields (状态压缩dp)
- POJ Corn Fields(状态压缩DP)
- POJ3254 Corn Fields (状态压缩DP)
- 【POJ3254】Corn Fields(状态压缩DP)
- POJ 3254 Corn Fields(状态压缩DP)
- poj 3254 Corn Fields (状态压缩dp)
- POJ3254——Corn Fields(状态压缩DP)
- poj 3254 Corn Fields(状态压缩DP)
- 状态压缩DP-Corn Fields(POJ 3254)
- 状态压缩dp入门 (poj3254 Corn Fields)
- POJ 3254 Corn Fields 状态压缩DP (C++/Java)
- POJ 3254 Corn Fields(状态压缩dp)
- POJ 3254 Corn Fields(状态压缩DP)
- poj 3254 Corn Fields(状态压缩DP)
- poj 3254 Corn Fields(状态压缩dp)
- [poj 3254] Corn Fields 状态压缩DP(递推)
- POJ 3254 Corn Fields(状态压缩DP)
- 哈夫曼树
- java集合中各个接口与实现类的区别
- JAVA String 类 总结(1)
- 求数组逆序对个数
- Codeforces 630H Benches
- poj3524 Corn Fields(状态压缩dp)
- linux基础学习之 gSOAP2.8.30在linux下的安装
- TCP、UDP、IP 协议分析
- 剑指offer-面试题35:第一个只出现一次的字符
- 配置和简单运行Heritrix3.2.0(环境为win10 64)
- BSD系统全家福
- Oracle PL/SQL异常处理
- 存储过程优点
- vagrant系列三:vagrant搭建的php7环境