明天计划上是要刷状压,但是作为现在还不会状压的\(ruoruo\)来说是一件非常苦逼的事情,所以提前学了一下状压\(dp\)。

鸣谢\(hmq\ juju\)的友情帮助

状态压缩动态规划

本博文的大体内容说明

因为刚学习状态压缩,并且刚做完一道例题。写博客的主要目的是怕自己忘掉,免得以后再重新学习一遍。而那些来踩我博客的同志们,希望以辩证的眼光来看待这篇博文。

于是这篇博客就讲\(Corn Fields\)这一道例题。所以阅读以下内容之前请先浏览一下题目。

基本原理

状态压缩\(dp\)主要是在二进制上进行状态转移的一种动态规划,因为每一个十进制的数可以表示成二进制,所以我们每一行的状态用一个十进制的数来储存。

状态压缩\(dp\)的主要工具

因为状态是在二进制上进行转移的,所以我们需要用到一些位运算来帮助我们进行状态转移。

  • |符号,表示或运算,0|1=1,1|1=1,1|0=1,0|0=0。
  • &符号,表示与运算,0&1=0,1&1=1,1&0=0,0&0=0。
  • 符号,表示异或运算,01=1,11=0,10=1,0^0=0。
  • <<符号,表示在2进制下小数点向右移动若干位,1<<2=4,3<<1=6。
  • >>符号,表示在2进制下小数点向左移动若干位,2>>1=1,13>>3=1。
  • 判断数字x第i位是否是1——if (x&(1<<i))。
  • 将一个数字x第i位改变为1——x|=(1<<i)。

状态压缩\(dp\)实现的基本过程

  1. 首先枚举所有的情况。根据题意,\(1\)表示有草,\(0\)表示没草,然后又有\(n\)位,所以我们就枚举\(0\sim2^n\)的位数,为啥尼?

    因为\(0\)表示没有草的情况,而\(2^n\)也就是\(\begin{matrix} \underbrace{ 1\cdots1 } \\ n\end{matrix}\)这种全是草的情况,所以要这样枚举。然后我们在存储合法状态,存到\(state\)数组里。
  2. 枚举完之后,我们的所有情况出来了,我们要进行存图,存图也要用二进制。这里我们存图用一个\(cur\)数组,这个数组表示图的存储,为了方便,我们将无草转变为\(1\),有草为\(0\)。
  3. 然后就是进行状态存储。我们已经有了合法状态,我们也有图,我们就要枚举判断合法状态内的可行状态。

    这里我们要用到一个\(fit\)函数。fit函数可以帮助我们判断合不合理,然后找到可行状态
  4. 状态转移。设\(dp[i][j]\)表示第\(i\)行的第\(j\)个状态。

    状态转移要枚举上一层的状态。然后方程很简单\(dp[i][j]=dp[i][j]+dp[i-1][k]\)。

例题代码讲解

首先我们看一下如何枚举状态

inline void init()//初始化
{
int sum=1<<n,i;//列举可能状态,并预存
for (i=0;i<sum;i++)
if (!(i&(i<<1)))//枚举合法状态
state[++tot]=i;
}

为什么\(!(i\&(i<<1))\)呢,因为你只要有牧草重叠,这个数绝对不会为\(0\)。

然后看一下图的存储

    for (i=1;i<=m;i++)
for (j=1;j<=n;j++)
{
k=read();
if (!k)
cur[i]+=(1<<(n-j));
}

为啥是左移\(n-j\)为呢\(?\)

因为你是从右往左来储存二进制的,第\(j\)位如果反过来肯定是第\(n-j\)位咯。

\(fit\)函数

inline bool fit(int x,int k)//判断当前状态是否符合当前行
{
return !(state[x]&cur[k]);
}

只要这一个函数理解了,状压就基本搞定了。

因为\(state\)存储的是合法状态,\(cur\)存储的是不合法状态,所以两者按位与,合法状态的数一定为\(0\),不合法状态的数一定不为\(0\)。这里有的同志就开始疑惑了,为啥尼?

你想想\(state\)里面\(1\)为有草,\(cur\)里面\(1\)为无草,而\(1\&1\)则代表有值,那么这个方案可行吗?

就这样我们能进行第一行的初始化咯

    for (i=1;i<=tot;i++)//初始化第一行
if (fit(i,1))
dp[1][i]=1;

状态转移

状态转移相对来说就比较简单了。

    for (i=2;i<=m;i++)//枚举行
for (j=1;j<=tot;j++)//枚举当前状态
{
if (!fit(j,i))//如果这一层的方案不在可行方案里
continue;
for (k=1;k<=tot;k++)//枚举上一层可行状态
{
if (!fit(k,i-1))//如果这一层的方案不在可行方案里
continue;
if (state[j]&state[k])//如果上一层的可行方案与这一层可行方案冲突,意思是上下有草挨着
continue;
dp[i][j]=(dp[i][j]+dp[i-1][k])%mod;//状态转移
}
}

具体可能的疑问都在代码中注释了

第一层枚举行数,第二层枚举可行方案,第三层枚举上一层的可行方案,万事大吉!

代码

#include<cstdio>
#include<iostream>
#include<cctype>
#define mod 100000000
#define C continue//懒得打hhhhh
using namespace std;
int n,m,tot,state[1500],dp[15][1500],ans,cur[15];//dp表示当前最大值,第一维是行数,第二维是状态数,cur是每行的情况,state是预存的可能状态
inline int read()//读入优化
{
int x=0,f=1;
char c=getchar();
while (!isdigit(c))
f=c=='-'?-1:1,c=getchar();
while (isdigit(c))
x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
} inline bool fit(int x,int k)//判断当前状态是否符合当前行
{
return !(state[x]&cur[k]);
} inline void init()//初始化
{
int sum=1<<n,i;//列举可能状态,并预存
for (i=0;i<sum;i++)
if (!(i&(i<<1)))//枚举合法状态
state[++tot]=i;
}
int main()
{
int i,j,k;
m=read();
n=read();
init();
for (i=1;i<=m;i++)
for (j=1;j<=n;j++)
{
k=read();
if (!k)
cur[i]+=(1<<(n-j));
}
for (i=1;i<=tot;i++)//初始化第一行
if (fit(i,1))
dp[1][i]=1;
for (i=2;i<=m;i++)//枚举行
for (j=1;j<=tot;j++)//枚举当前状态
{
if (!fit(j,i))//如果这一层的方案不在可行方案里
continue;
for (k=1;k<=tot;k++)//枚举上一层可行状态
{
if (!fit(k,i-1))//如果这一层的方案不在可行方案里
continue;
if (state[j]&state[k])//如果上一层的可行方案与这一层可行方案冲突,意思是上下有草挨着
continue;
dp[i][j]=(dp[i][j]+dp[i-1][k])%mod;//状态转移
}
}
for (i=1;i<=tot;i++)
ans=(ans+dp[m][i])%mod;
printf("%d",ans);
return 0;
}

状态压缩dp初学__$Corn Fields$的更多相关文章

  1. 【原创】【状态压缩DP】POJ3254 Corn Fields【新手向】

    一开始根本不会状压dp,上网各种找题解,但发现他们写的都很......反正我作为一个没有接触过状态压缩的,根本看不懂! 然后看了好多状态压缩的题的题解,总结了一下思路,思路很重要,有了思路转换成计算机 ...

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

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

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

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

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

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

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

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

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

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

  7. 状压DP POJ 3254 Corn Fields

    题目传送门 /* 状态压缩DP:先处理硬性条件即不能种植的,然后处理左右不相邻的, 接着就是相邻两行查询所有可行的种数并累加 写错一个地方差错N久:) 详细解释:http://www.tuicool. ...

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

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

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

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

随机推荐

  1. xftp和xshell的使用

    Xftp和Xshell配合使用部署环境. (linux系统) Xftp为可视化工具.主要用来复制文件. xshell则通过输入命令来对server进行操作,如启动服务等等. 一.  Xftp的连接 新 ...

  2. 华硕 X201E 拆机

    每次笔记本拆机,装好之后.就会发现多了几个螺丝,忘了从哪拧下来了 以下记录下华硕 X201E 清灰拆机过程 1:电脑正面图 2:背面图,一共9个螺丝 3:背面的9个螺丝拧下来,把后盖沿着缝隙扣下来 w ...

  3. Linux下iscsi的使用

    查看是否已安装了iscsi-initiator:  [root@test\ ~]# rpm -qa |grep iscsi iscsi-initiator-utils-6.2.0.868-0.18.e ...

  4. 整数转罗马数字 C++实现 java实现 leetcode系列(十二)

    罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如, 罗马数字 2 写做 II ,即为两个并 ...

  5. java.lang.NoClassDefFoundError: org/springframework/dao/support/PersistenceE解决方法

    笔者是使用spring4.0时,报的错误: 原因是没有引入spring-tx-4.0.0.RELEASE.jar包,將spring-tx-4.0.0.RELEASE.jar添加到build path中 ...

  6. HTML基础——网站信息显示页面

    1.语法和规范 HTML文件都是以.html或者.htm结尾的.建议使用.html结尾. HTML文件分为头部分(<head></head>)和体部分(<body> ...

  7. QT笔记 -- (2) 文件相关操作、中文路径乱码

    1.显示文件对话框,选择一个目录,显示选中目录中的所有图片的代码如下 主要class: QFileDialog QStringList QFileInfoList QDir void open(){ ...

  8. easyui的datagrid右侧没有边框线

    做项目时,用的easyui的框架的datagrid,运行时发现右侧没有边框,其它的都有边框,使用网页的审查元素可以看到datagrid样式里的宽度没有自动减去2个像素,这些都是easyui自算的宽高, ...

  9. eclipse的springMVC环境搭建并输出HelloWorld

    spring简单介绍:https://www.cnblogs.com/package-java/p/10368672.html 1.创建一个Maven Project项目 点击下一步 点击下一步 2. ...

  10. JAVA调用接口

    HttpUrlconnection部分 //发送JSON字符串 如果成功则返回成功标识. public static String doJsonPost(String urlPath, String ...