一开始根本不会状压dp,上网各种找题解,但发现他们写的都很......反正我作为一个没有接触过状态压缩的,根本看不懂!

然后看了好多状态压缩的题的题解,总结了一下思路,思路很重要,有了思路转换成计算机语言就好了。因此我先讲一下思路:

  先说说地图,地图上每一行的01代表一个状态,比如输入样例中的111、010,表示第一行的三个位置都可以种稻子,第二行中间的位置可以种稻子,然后,不能种稻子的地方一定不能种稻子(废话...)

可以种稻子的地方可以选择种也可以选择不种,然后有一个前提条件,就是上下左右相邻的地方不能种稻子。

  再说说怎么状态压缩,状态压缩就是把每一个状态压缩成二进制,二进制就是由01组成的,0代表不种,1代表种。二进制就要牵扯到位运算,位运算我就不想说了,百度吧。因此,一串01的二进制数就

可以代表一个状态,例如输入样例第一行是111,那么可以放入第一行的状态有,100、010、001、101、000,因为相邻位置不能放所以只有5种方法,那么第二行就只有2种方法000、010(不考虑其他行)

  那么看第一行和第二行(第一行——第二行),100——000,010——000,001——000,101——000,000——000,这是5种对应方法,还可以100——010,001——010,101——010,000——010这是另外的4种对应方法(第一行5种状态对吧?第二行2种状态,按照乘法原理,应该有5*2 = 10种方法,但是111——010是不合法的,因此样例的答案是10-1 = 9)。

dp[i][j]意思是推到第i行状态为j的方案总数。

那么“100——000”即为dp[2][000]可以由dp[1][100]得到,那么dp[2][000] = dp[2][000] + dp[1][100];

那么“010——000”即为dp[2][000]可以由dp[1][010]得到,那么dp[2][000] = dp[2][000] + dp[1][010];

......

以此类推,逐行递推。

  总结一下思路:先枚举第一行,把所有可能的状态和第一行的地图对比,如果成功,则在循环里继续枚举第二行,把所有可能的状态和第二行的地图对比,如果成功,再和第一行填入的状态对比,如果又匹配成功,则dp[2][000] = dp[2][000] + dp[1][100];方法数加到第二行。这就是一次循环结束了,从新枚举第二行...

把思路转换成代码

can[]代表可行的状态,稍后解释。cur[i]代表地图的第i行
1 for(int i=;i<m;i++)//枚举每一行
{
for(int j=;j<tot;j++)//对第i行枚举所有可行的状态j
{
if((can[j]&cur[i])==)//如果状态j和第i行匹配了
{
for(int k=;k<tot;k++)//枚举第i+1行的所有可行的状态k
{
if(((can[k]&cur[i+])==)&&((can[k]&can[j])==))//状态k和第i+1行匹配且和状态j匹配
dp[i+][can[k]] = dp[i+][can[k]]+dp[i][can[j]];//状态数相加
}
}
}
}

这样核心代码就实现了。

有一个小方法,就是枚举可行状态的时候,假如一行是8列,不必从00000000枚举到11111111,这样很麻烦,所以要预处理。

就是在一开始把,一行的可行状态先求出来就拿“11111111”来说,这肯定是不可能的,因为有相邻的1,所以在一开始就可以舍弃掉。怎么做呢?

假如一行是8列,先从00000000枚举到11111111,对于每一个状态把它左移1位,再和他自己&运算,假如结果>0,就说明有有相邻的1,举个简单的例子:

  01011要判断有没有相邻的1,if(((01011<<1) & (01011)) > 0 )则有相邻的1,(01011<<1) & (01011) 就是 01010和0101按位且运算,这两个红色地方1&1 == 1,因此结果大于0。

怎么实现呢?

 tot = ;//全局变量,相当于栈的top,代表可行的状态数
for(int i=;i<(<<n);i++)//n是列数,i是枚举的状态
if((i&(i<<))==) can[tot++] = i;

  dp[][]肯定要初始化对吧?不然全是0了,只要对第一行初始化就行了,因为后面的的行都是由第一行得来的

 for(int i=;i<tot;i++)
if((cur[]&can[i])==) dp[][can[i]] = ;//和cur[1](第一行)匹配,就给对应的dp赋值为1

  最后一步就是得到cur[]

 for(int i=;i<=m;i++)
{
for(int j=;j<n;j++)
{
int num;
scanf("%d",&num);
if(num==) cur[i] = (cur[i]|(<<j));//这里要给0的地方变为1,1的地方放上0,因为要保证不合法的匹配一定是独一无二的。自己思考一下吧
}
}

最后贴一下完整代码,一开始学的时候,感觉主流代码都一模一样,而且一大堆乱七八糟的函数,麻烦又看不懂,于是下定决心如果自己搞明白了,一定要写一个大家都看得懂的题解,感觉自己讲的比其他都清楚了,如果看不懂就真没办法了......

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define mod 100000000 using namespace std;
int dp[][<<],cur[];
int can[<<],tot,m,n; int main()
{
while(~scanf("%d%d",&m,&n))
{
tot = ;
for(int i=;i<(<<n);i++)
if((i&(i<<))==) can[tot++] = i;
memset(cur,,sizeof(cur));
memset(dp,,sizeof(dp));
for(int i=;i<=m;i++)
{
for(int j=;j<n;j++)
{
int num;
scanf("%d",&num);
if(num==) cur[i] = (cur[i]|(<<j));
}
}
for(int i=;i<tot;i++)
if((cur[]&can[i])==) dp[][can[i]] = ;
for(int i=;i<m;i++)
{
for(int j=;j<tot;j++)
{
if((can[j]&cur[i])==)
{
for(int k=;k<tot;k++)
{
if(((can[k]&cur[i+])==)&&((can[k]&can[j])==))
dp[i+][can[k]] = dp[i+][can[k]]+dp[i][can[j]];
}
}
}
}
int ans = ;
for(int i=;i<tot;i++)
{
ans += dp[m][can[i]];
ans = ans % mod;
}
printf("%d\n",ans);
}
}

【原创】【状态压缩DP】POJ3254 Corn Fields【新手向】的更多相关文章

  1. POJ3254 - Corn Fields(状态压缩DP)

    题目大意 给定一个N*M大小的土地,土地有肥沃和贫瘠之分(每个单位土地用0,1来表示贫瘠和肥沃),要求你在肥沃的单位土地上种玉米,如果在某个单位土地上种了玉米,那么与它相邻的四个单位土地是不允许种玉米 ...

  2. poj3254 Corn Fields 利用状态压缩求方案数;

    Corn Fields 2015-11-25 13:42:33 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 10658   ...

  3. POJ 3254 Corn Fields(状态压缩DP)

    Corn Fields Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4739   Accepted: 2506 Descr ...

  4. 状态压缩dp初学__$Corn Fields$

    明天计划上是要刷状压,但是作为现在还不会状压的\(ruoruo\)来说是一件非常苦逼的事情,所以提前学了一下状压\(dp\). 鸣谢\(hmq\ juju\)的友情帮助 状态压缩动态规划 本博文的大体 ...

  5. POJ 3254 Corn Fields (状态压缩DP)

    题意:在由方格组成的矩形里面种草,相邻方格不能都种草,有障碍的地方不能种草,问有多少种种草方案(不种也算一种方案). 分析:方格边长范围只有12,用状态压缩dp好解决. 预处理:每一行的障碍用一个状态 ...

  6. 【bzoj1725】[USACO2006 Nov]Corn Fields牧场的安排 状态压缩dp

    题目描述 Farmer John新买了一块长方形的牧场,这块牧场被划分成M列N行(1<=M<=12; 1<=N<=12),每一格都是一块正方形的土地.FJ打算在牧场上的某几格土 ...

  7. POJ Corn Fields 状态压缩DP基础题

    题目链接:http://poj.org/problem?id=3254 题目大意(名称什么的可能不一样,不过表达的意思还是一样的): 种玉米 王小二从小学一年级到现在每次考试都是班级倒数第一名,他的爸 ...

  8. POJ3254(入门状态压缩dp)

    Corn Fields Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 13203   Accepted: 6921 Desc ...

  9. 状态压缩DP(大佬写的很好,转来看)

    奉上大佬博客 https://blog.csdn.net/accry/article/details/6607703 动态规划本来就很抽象,状态的设定和状态的转移都不好把握,而状态压缩的动态规划解决的 ...

  10. 关于状态压缩DP以及状态压缩

    首先要明确:状态压缩是利用数字来代表一组序列的方法,从而降低序列访问的复杂度,本质上跟HASH有着差不多的思想,但是其实就是数位运算的一种 定义:集合中共有N个数字,其中每个数字均小于K,能么我们可以 ...

随机推荐

  1. Pair Project

    以前只是一个人完成一个项目,不论什么都是,现在突然要两个人一起来写, 听上去挺稀奇的,也挺简单的,可惜了就是“听上去”而已.我认为这也是一种技术啊~ 我跟我的搭档研究了好久好久,选择了好久,然后也选了 ...

  2. js总结:利用js获取下拉框的value值和文本值

    select下拉框在项目开发中是经常用到的,特别是在联级菜单方面的应用更为广泛.但是,对于一些初学者来说,如何获取下拉框子节点option的value值和文本内容,还是有一点难度的. html代码: ...

  3. Python之列表

    一.列表的特点 列表也是一种数据类型 列表元素是有序的,有编号的 列表元素的下标从0开始 列表中的每一个值叫一个元素,编号叫下标(索引/角标): stu_name=['崔海龙','杨帆','lrx', ...

  4. scp Permission denied

    https://blog.csdn.net/xlgen157387/article/details/49818259

  5. Swagger UI 用法

    Swagger - 简书https://www.jianshu.com/p/4115f2b53983 Swagger简介 - Ghost Stories - CSDN博客https://blog.cs ...

  6. 使用node操作mongodb

    let mongodb = require('mongodb'); let MongodbClient = mongodb.MongoClient; MongodbClient.connect('mo ...

  7. day 7-2 multiprocessing开启多进程

    一. multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu\_count\(\)查看),在python中大部分情况需要使用多 ...

  8. C#Note13:如何在C#中调用python

    前言 IronPython 是一种在 .NET 及 Mono上的 Python 实现,由微软的 Jim Hugunin(同时也是 Jython 创造者) 所发起,是一个开源的项目,基于微软的 DLR ...

  9. Spring Boot基础:Spring Boot简介与快速搭建(1)

    1. Spring Boot简介 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化Spring应用的创建.运行.调试.部署等. Spring Boot默认使用tomca ...

  10. Tomcat配置Https环境

    windows环境下:http://blog.csdn.net/supersky07/article/details/7407523 linux环境下:http://blog.csdn.net/cuk ...