状压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是当前行

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

代码

  1. #include<iostream>
  2. #include<string.h>
  3. #include<cstdio>
  4. #include<algorithm>
  5. using namespace std;
  6. #define ll long long
  7. ll dp[15][2200];
  8. int n,m;
  9. //dp[i][j]//表示第i列状态为j时的方案数
  10. void dfs(int i,int j,int state,int next){
  11. //i表示行,j表示列,state表示当前状态,next表示到达下一列的状态
  12. if(i==n){
  13. //当前列已经到达第n+1行了
  14. //下面有说 i是表示第i+1行的
  15. dp[j+1][next]+=dp[j][state];
  16. return;
  17. }
  18. else{
  19. //如果当前列的当前行被占用过了往下一行搜索
  20. if((state&(1<<i))){
  21. //特别注意i是表示第i+1行的状态不是i行
  22. //因为本来1在做好一位左移了i位它的位置在第i+1了,右边数起
  23. dfs(i+1,j,state,next);
  24. }
  25. //如果当前格子没被占就可以放一个1*2,下一列就会改变状态
  26. if((state&(1<<i))==0)
  27. dfs(i+1,j,state,next|(1<<i));
  28. //如果当前格子和下一行的格子都不被占用就可以放一个2*1下一列不会改变状态
  29. //还得判断是否超出最下面那行
  30. if(i+1<n&&(state&(1<<i))==0&&(state&(1<<(i+1)))==0)
  31. dfs(i+2,j,state,next);
  32. }
  33. }
  34. int main(){
  35. //freopen("in.txt","r",stdin);
  36. while(~scanf("%d%d",&n,&m)&&(n+m)){
  37. if(n>m) swap(n,m);
  38. memset(dp,0,sizeof(dp));
  39. dp[1][0]=1;
  40. for(int i=1;i<=m;i++)
  41. for(int j=0;j<(1<<n);j++)
  42. if(dp[i][j]>0) dfs(0,i,j,0);//如果有某种状态转移到该状态才会进行填充
  43. //第m列刚好填充满而且第m+1列是没有的才是答案
  44. printf("%lld\n",dp[m+1][0]);
  45. }
  46. return 0;
  47. }

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)

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

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

代码

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<string.h>
  4. #include<cstdio>
  5. using namespace std;
  6. const int N=(1<<12)+10;
  7. const int mod=1e8;
  8. int a[20][20],dp[20][N];
  9. //dp[i][j]表示第i列状态为j的方案数
  10. int n,m;
  11. void dfs(int i,int j,int state,int next,bool flag){
  12. //参数分别是行 列 状态 下一列状态 上一行是否种玉米
  13. //一定注意“”i表示的是第i+1行
  14. if(i==n){
  15. dp[j+1][next]=(dp[j+1][next]+dp[j][state])%mod;
  16. return;
  17. }
  18. else{
  19. //可以种,(i,j)这个位置为1,因为i表示的是第i+1行
  20. //而实际中他的位置是a[i+1][j];
  21. if(a[i+1][j]==1&&(state&(1<<i))==0&&flag==0){
  22. //有两种选择种或者不种
  23. dfs(i+1,j,state,next|(1<<i),1);
  24. dfs(i+1,j,state,next,0);
  25. }
  26. else dfs(i+1,j,state,next,0);
  27. }
  28. }
  29. int main(){
  30. freopen("in.txt","r",stdin);
  31. while(~scanf("%d%d",&n,&m)){
  32. memset(a,0,sizeof(a));
  33. for(int i=1;i<=n;i++)
  34. for(int j=1;j<=m;j++)
  35. cin>>a[i][j];
  36. memset(dp,0,sizeof(dp));
  37. dp[1][0]=1;
  38. for(int i=1;i<=m;i++)
  39. for(int j=0;j<(1<<n);j++)
  40. if(dp[i][j]>0)
  41. dfs(0,i,j,0,0);
  42. int sum=0;
  43. for(int i=0;i<(1<<n);i++)
  44. if(dp[m+1][i]>0)
  45. sum=(sum+dp[m+1][i])%mod;
  46. printf("%d\n",sum);
  47. }
  48. return 0;
  49. }

算法笔记-状压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. Python之celery的简介与使用

    celery的简介   celery是一个基于分布式消息传输的异步任务队列,它专注于实时处理,同时也支持任务调度.它的执行单元为任务(task),利用多线程,如Eventlet,gevent等,它们能 ...

  2. MEF 基础简介 一

    前言 小编菜鸟级别的程序员最近感慨颇多,经历了三五春秋深知程序路途遥远而我沧海一粟看不到的尽头到不了的终点何处是我停留的驿站.说了段废话下面进入正题吧! 什么是MEF? MEF:全称Managed E ...

  3. Java学习--使用 Date 和 SimpleDateFormat 类表示时间

    使用 Date 和 SimpleDateFormat 类表示时间 在程序开发中,经常需要处理日期和时间的相关数据,此时我们可以使用 java.util 包中的 Date 类.这个类最主要的作用就是获取 ...

  4. 【代码笔记】Web-CSS-CSS Margin(外边距)

    一,效果图. 二,代码. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  5. 荣耀MagicBook黑苹果(i7)High Sierra 10.13.6

    这里有大佬维护的新版本EFI,对应10.14.4:https://github.com/hjmmc/Honor-Magicbook ---------------------------------- ...

  6. 【阿里云】在 Windows Server 2016 下使用 FileZilla Server 安装搭建 FTP 服务

     Windows Server 2016 下使用 FileZilla Server 安装搭建 FTP 服务 一.安装 Filezilla Server 下载最新版本的 Filezilla Server ...

  7. 可视化设计,类Excel的快速开发平台

    活字格Web应用生成器,是可视化设计,类Excel的快速开发平台,接下来给大家介绍如何体现这些特点. 一.可视化设计 网页系统的开发,包含UI设计+代码编写的工作,最终形成网页系统.这要求系统开发人员 ...

  8. Android预置Apk方法

    这一套8.0过时了 需要修改pms代码 否则apk会被pms删除掉 因为工作需要,经常要开发和合入系统App,所以在此开篇作为收集和记录Android合入系统应用的方法,以备日后查阅. 一.预置apk ...

  9. 测者的测试技术笔记:揭开java method的一个秘密--巨型函数

    相信,很多人都不知道Java的Method的上限为64K.本文将超过这个上限的函数叫做巨型函数. 巨型函数的问题 1.如果代码超过了这个限制,Java编译器就报"Code too large ...

  10. CentOS7 设置yum源

    1.关闭防火墙 临时关闭防火墙 systemctl stop firewalld 永久防火墙开机自关闭 systemctl disable firewalld 临时打开防火墙 systemctl st ...