状压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. C#委托与事件学习笔记

    委托事件学习笔记 本文是学习委托和事件的笔记,水平有限,如有错漏之处,还望大神不吝赐教. 什么是委托?从字面意思来解释,就是把一个动作交给别人去执行.在实际开发中最常用的就是使一个方法可以当做一个参数 ...

  2. 第一个用eclipse打包APK时报错一个错误怎么解决

    这个问题也是我在android开发群里面解决的一个问题. 如果有什么想法或者想法可以在下面进行评论,我们可以一起交流一下! 我们在eclipse中开发完一个程序之后,需要将其打包为APK的安装包,我们 ...

  3. Html和Css学习笔记-css进阶-盒模型

    我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! 此篇博客是我的复习笔记,html和css学的时间太久了,忘得差不多了,最近要使用一下,所以重新打开html的书略读,后记录了标签 ...

  4. arcgis api 3.x for js入门开发系列九热力图效果(附源码下载)

    前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...

  5. EditText超出字数限制,给用户提示

    当我们在Editext输入内容的时候,检测如果超过限制的长度无法输入内容,并且给用户提示. 首先我想到了下面的方法: editText.addTextChangedListener(new TextW ...

  6. RecycleView设置顶部分割线(记录一个坑)

    大家都知道,想给RecycleView设置分割线可以重写RecyclerView.ItemDecoration 项目过程中,遇到一个需求:RecycleView顶部有一条灰色的间隔,我想到了给Recy ...

  7. 小米Max 2获取ROOT超级权限的经验

    小米Max 2有么好方法开通了root权限?大家都了解,安卓手机有root权限,如果手机开通了root相关权限,能够实现更完美的功能,打比方大家企业的营销部门的同事,使用某些营销工具都需要在root权 ...

  8. 版本控制工具(SVN/Git)介绍

    文章大纲 一.SVN介绍二.Git介绍三.IDEA使用SVN和Git四.总结五.参考文章   一.SVN介绍 1. SVN服务器搭建和使用 首先来下载和搭建SVN服务器,下载地址如下: http:// ...

  9. 【English】一、专治各种英语不服

    一.前言 英语虽然不是使用人数最多的语言,但是...谁叫我是一名码农且英语垃圾呢. 二.开始 1. read sb sth = read sth for sb read sb sth 是双宾语结构. ...

  10. 【转贴】一次 JDBC 与 MySQL 因 “CST” 时区协商误解导致时间差了 14 或 13 小时的排错经历

    原文:https://juejin.im/post/5902e087da2f60005df05c3d ------------------------------------------------- ...