状压dp

就是把状态压缩的dp

这样还是一种暴力但相对于纯暴力还是优雅的多。

实际上dp就是经过优化的暴力罢了

首先要了解位运算

给个链接吧

[https://blog.csdn.net/u013377068/article/details/81028453]

一些例题

之所以很难理解是因为没搞懂那些位运算的特点

在接下来的代码中会讲

poj 2411

[http://poj.org/problem?id=2411]

就是给你一个mn的网格,有两种砖12和2*1;

问你刚好填满的方案有多少

分析

首先你放置的时候会受到前一列影响,当前的放置也会队下一列有影响

假设你要放的位置有了就不能放了,再往下一行放

如果该位置没有就可以放一个12的,但它会对下一列有影响所以你得记录产生的影响

如果该位置没有且它下面也没有被占用就可以放一个2
1

之后你得跳到i+2行去放了 i是当前行

代码里说了很多关键的东西自己看吧

代码

#include<iostream>
#include<string.h>
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
ll dp[15][2200];
int n,m;
//dp[i][j]//表示第i列状态为j时的方案数
void dfs(int i,int j,int state,int next){
//i表示行,j表示列,state表示当前状态,next表示到达下一列的状态
if(i==n){
//当前列已经到达第n+1行了
//下面有说 i是表示第i+1行的
dp[j+1][next]+=dp[j][state];
return;
}
else{
//如果当前列的当前行被占用过了往下一行搜索
if((state&(1<<i))){
//特别注意i是表示第i+1行的状态不是i行
//因为本来1在做好一位左移了i位它的位置在第i+1了,右边数起
dfs(i+1,j,state,next);
}
//如果当前格子没被占就可以放一个1*2,下一列就会改变状态
if((state&(1<<i))==0)
dfs(i+1,j,state,next|(1<<i));
//如果当前格子和下一行的格子都不被占用就可以放一个2*1下一列不会改变状态
//还得判断是否超出最下面那行
if(i+1<n&&(state&(1<<i))==0&&(state&(1<<(i+1)))==0)
dfs(i+2,j,state,next);
} }
int main(){
//freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&m)&&(n+m)){
if(n>m) swap(n,m);
memset(dp,0,sizeof(dp));
dp[1][0]=1;
for(int i=1;i<=m;i++)
for(int j=0;j<(1<<n);j++)
if(dp[i][j]>0) dfs(0,i,j,0);//如果有某种状态转移到该状态才会进行填充
//第m列刚好填充满而且第m+1列是没有的才是答案
printf("%lld\n",dp[m+1][0]);
}
return 0;
}

poj 3254

[http://poj.org/problem?id=3254]

题意就是给你

一个矩阵 某个位置是0不可以种,1可以种

而且相邻的不能种也就是上下左右不能种

为你有多少种 种法

分析

对于某个位置该不该种你得看你左边和上边,因为我们是从第一列往右1列1列地选择种的方式不用考虑下面和左边

每一列的状态比如5=(101)表示该列的第一行和第三行都已经种了玉米,第二行没种

最后定义状态和转移方程

dp[i][j]表示第i列状态为j的方案数

dfs(int i,int j,int state,int next,bool flag)

//参数分别是行 列 状态 下一列状态 上一行是否种玉米

结果就是最后列所以状态之和

代码

#include<iostream>
#include<algorithm>
#include<string.h>
#include<cstdio>
using namespace std;
const int N=(1<<12)+10;
const int mod=1e8;
int a[20][20],dp[20][N];
//dp[i][j]表示第i列状态为j的方案数
int n,m;
void dfs(int i,int j,int state,int next,bool flag){
//参数分别是行 列 状态 下一列状态 上一行是否种玉米
//一定注意“”i表示的是第i+1行
if(i==n){
dp[j+1][next]=(dp[j+1][next]+dp[j][state])%mod;
return;
}
else{
//可以种,(i,j)这个位置为1,因为i表示的是第i+1行
//而实际中他的位置是a[i+1][j];
if(a[i+1][j]==1&&(state&(1<<i))==0&&flag==0){
//有两种选择种或者不种
dfs(i+1,j,state,next|(1<<i),1);
dfs(i+1,j,state,next,0);
}
else dfs(i+1,j,state,next,0);
}
}
int main(){
freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&m)){
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j]; memset(dp,0,sizeof(dp));
dp[1][0]=1; for(int i=1;i<=m;i++)
for(int j=0;j<(1<<n);j++)
if(dp[i][j]>0)
dfs(0,i,j,0,0);
int sum=0;
for(int i=0;i<(1<<n);i++)
if(dp[m+1][i]>0)
sum=(sum+dp[m+1][i])%mod;
printf("%d\n",sum);
}
return 0;
}

算法笔记-状压dp的更多相关文章

  1. 【洛谷5492】[PKUWC2018] 随机算法(状压DP)

    点此看题面 大致题意: 用随机算法求一张图的最大独立集:每次随机一个排列,从前到后枚举排列中的点,如果当前点加入点集中依然是独立集,就将当前点加入点集中,最终得到的点集就是最大独立集.求这个随机算法的 ...

  2. [学习笔记]状压dp

    状压 \(dp\) 1.[SDOI2009]Bill的挑战 \(f[i][j]\) 表示匹配到字符串的第 \(i\) 位状态为 \(j\) 的方案数 那么方程就很明显了,每次枚举第 \(i\) 位的字 ...

  3. loj2540 「PKUWC2018」随机算法 【状压dp】

    题目链接 loj2540 题解 有一个朴素三进制状压\(dp\),考虑当前点三种状态:没考虑过,被选入集合,被排除 就有了\(O(n3^{n})\)的转移 但这样不优,我们考虑优化状态 设\(f[i] ...

  4. 算法复习——状压dp

    状压dp的核心在于,当我们不能通过表现单一的对象的状态来达到dp的最优子结构和无后效性原则时,我们可能保存多个元素的有关信息··这时候利用2进制的01来表示每个元素相关状态并将其压缩成2进制数就可以达 ...

  5. LOJ2540 [PKUWC2018] 随机算法 【状压DP】

    题目分析: 听说这题考场上能被$ O(4^n) $的暴力水过,难不成出题人是毕姥爷? 首先思考一个显而易见的$ O(n^2*2^n) $的暴力DP.一般的DP都是考虑最近的加入了哪个点,然后删除后递归 ...

  6. 【51Nod】1920 空间统计学 状压DP

    [题目]1920 空间统计学 [题意]给定m维空间中的n个点坐标,满足每一维坐标大小都在[0,3]之间,现在对于[0,3*m]的每个数字x统计曼哈顿距离为x的有序点对数.\(n \leq 2*10^5 ...

  7. 【BZOJ】2004: [Hnoi2010]Bus 公交线路 状压DP+矩阵快速幂

    [题意]n个点等距排列在长度为n-1的直线上,初始点1~k都有一辆公车,每辆公车都需要一些停靠点,每个点至多只能被一辆公车停靠,且每辆公车相邻两个停靠点的距离至多为p,所有公车最后会停在n-k+1~n ...

  8. 「算法笔记」状压 DP

    一.关于状压 dp 为了规避不确定性,我们将需要枚举的东西放入状态.当不确定性太多的时候,我们就需要将它们压进较少的维数内. 常见的状态: 天生二进制(开关.选与不选.是否出现--) 爆搜出状态,给它 ...

  9. 状压dp(状态压缩&&dp结合)学习笔记(持续更新)

    嗯,作为一只蒟蒻,今天再次学习了状压dp(学习借鉴的博客) 但是,依旧懵逼·································· 这篇学习笔记是我个人对于状压dp的理解,如果有什么不对的 ...

随机推荐

  1. 以太仿DApp开发环境搭建

    在网上找了些以太仿的资料,是node.js写的,之前也了解过node.js,正好也可以用上.本篇主要学习以太仿DApp开发环境搭建. 一.安装 DApp 开发环境 1.1安装 Node.js 首先下载 ...

  2. MySQL单行函数

    1.CONCAT(str1,str2,...) 返回来自于参数连结的字符串.如果任何参数是NULL,返回NULL.可以有超过2个的参数.一个数字参数被变换为等价的字符串形式.  select CONC ...

  3. JS 无限长form表单提交

    1 简介 开发时候,总会遇到根据后台传的变量{组件数}来动态渲染组件的情况,比如后台传命令要绑定10个父子关系,则前台展开十个input组件,后台决定绑定5个福字关系,则前台展开5个input组件.再 ...

  4. 此博客停更,转至lustforlife.cn

    新博客地址:lustforlife.cn

  5. 少侠学代码系列(二)->JS实现

    少侠:小子,休息好了没,赶紧的 帅气的我:好了好了,嚷什么 少侠:(拔刀)嗯? 帅气的我:少侠,淡定淡定,我们来看秘籍吧,刚刚我们说了JS实现是由三个部分组成的 核心(ECMAScript),文档对象 ...

  6. (最详细)小米MIX的Usb调试模式在哪里打开的教程

    当我们使用安卓手机链接pc的时候,或者使用的有些应用比如我们团队营销团队当使用的应用引号精灵,以前老版本就需要开启Usb调试模式下使用,现当新版本不需要了,如果手机没有开启Usb调试模式,pc则没法成 ...

  7. 使用cmd查看电脑连接过的wifi密码(一)

    有时总会忘记之前的wifi密码,这时候就需要查看wifi密码: 这个我就写了一个bat文件,方便下次使用,这里我添加了中文和英文的判断,主要是语言不同输出的信息不用,不说了直接上代码: @echo o ...

  8. python 实例六

    https://www.cnblogs.com/evablogs/p/6783498.html 题目:斐波那契数列. 程序分析:这个数列从第3项开始,每一项都等于前两项之和.故 n=1,2,f=1 n ...

  9. JS时间的获取及格式

    最近在做一个web聊天室,一个时间的问题挡住了进程,只好全网大搜索,将实用的方法记录下来,以备后查 <script src="/static/bootstrap/js/jquery.m ...

  10. Java 位运算符和 int 类型的实现

    Java 位运算符和 int 类型的实现 其他运算符 # 算术运算符 +.-.*./.++i.i++.--i.i-- # 关系运算符 ==.!=.>.<.>=.<= # 逻辑运 ...