一开始根本不会状压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. shell脚本--php执行普通shell命令

    这里只演示一些普通的shell命令,一些需要root用户权限执行的命令,请参考:php以root权限执行shell命令 php执行shell命令,可以使用下面几个函数: string system ( ...

  2. 对于vue和react“页面间”传递数据的理解误区

    前言 如果我们想要实现多个标签页之间的通信,可以使用localStorage.cookie等,但是能不能用vue或react呢? 结论 答案是NO,因为vue和react虽然可以在“多个”页面之间传递 ...

  3. Windows 下面 redis 发布为服务的官方方法

    除了 NSSM 之外 另外一种方式 感觉还是很好用的 redis-server --service-install redis.windows.conf --loglevel verbose 感觉也可 ...

  4. getMessage(),getFile,getLine获取异常用法

    try { $param = $request->all(); $param['building_id'] = 0; $param['sync'] = 2; // 1小程序2App $param ...

  5. java.lang.NoClassDefFoundError: org/apache/log4j/Priority的问题解决

    在pom 文件中添加 <dependency> <groupId>log4j</groupId> <artifactId>log4j</artif ...

  6. Swagger2常用注解及其说明 (转)

    Api 用在Controller中,标记一个Controller作为swagger的文档资源 属性名称 说明 value Controller的注解 description 对api资源的描述 hid ...

  7. elasticsearch索引合并

    参考地址:http://cwiki.apachecn.org/display/Elasticsearch/Reindex+API 1.首先插入准备数据,创建两个索引. (1).PUT  http:// ...

  8. 【python练习题】程序13

    #题目:打印出所有的"水仙花数",所谓"水仙花数"是指一个三位数,其各位数字立方和等于该数本身.例如:153是一个"水仙花数",因为153= ...

  9. 思路 一般创建展示类时候 例如page类 会在网页上新增多个对应字段的隐藏域 用于存储值

    思路 一般创建展示类时候 例如page类 会在网页上新增多个对应字段的隐藏域 用于存储值

  10. 高仿Readhub小程序 微信小程序项目【原】

    # News #### 项目介绍微信小程序项目涉及功能 https://gitee.com/richard1015/News https://github.com/richard1015/News 高 ...