状压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. Chrome F12调试工具常用技巧

    原文地址:http://www.cnblogs.com/MuYunyun/p/5678405.html#3471461 阅读目录 Chrome调试工具介绍: 快速切换文件 在源代码中搜索 在源代码中快 ...

  2. .Net Core 实践 - 使用log4net记录日志(1)

    demo地址:https://github.com/PuzzledAlien/log4net_demo 准备 log4net 最新版本是2.0.8 VS2017 .Net Core 2.2 测试电脑配 ...

  3. [转]react 部署在ngnix上(windows环境)

    本文转自:https://blog.csdn.net/wly_er/article/details/82348593 目录 1.下载nginx. 2.测试nginx 3.配置react项目 4.ngi ...

  4. 【java】随机生成6位的数字

    int radomInt = new Random().nextInt(999999); int radomInt2 =(int)((Math.random()*9+1)*100000); Syste ...

  5. mysql修改连接数

    方法一:   进入MySQL安装目录 打开MySQL配置文件 my.ini 或 my.cnf查找 max_connections=100 修改为 max_connections=1000 服务里重起M ...

  6. SDOI 2018划水记

    Day0 最后一天啦,此时不颓更待何时? 上午10:15坐车从gryz出发,在一路颓废中到了农大 不得不说,农大的宾馆真的好高档啊,壁橱里面居然有保险柜!电视柜厨子里居然有冰箱!!冰箱里居然有饮料!! ...

  7. 谷歌浏览器扩展程序manifest.json参数详解

    { // Required "manifest_version": 2, // manifest编写规范版本,目前主流2 "name": "My Ex ...

  8. 配置ADB到Windows环境变量

    adb 命令可以帮我们快速的管理连接的手机设备,例如执行一些安装apk,卸载apk命令,对于熟悉linux系统的人,可以方便的管理手机目录操作手机文件,还可以通过adb命令查看手机的系统日志等操作. ...

  9. Kubernetes 集群日志管理 - 每天5分钟玩转 Docker 容器技术(180)

    Kubernetes 开发了一个 Elasticsearch 附加组件来实现集群的日志管理.这是一个 Elasticsearch.Fluentd 和 Kibana 的组合.Elasticsearch ...

  10. office2019下载以及激活密钥(亲测可用)

    office2019激活密钥 W8W6K-3N7KK-PXB9H-8TD8W-BWTH9  或者: 链接:https://pan.baidu.com/s/1Ch0rc2ZN9I_lwmbjGESTuw ...