状压dp,就是把动态规划之中的一个个状态用二进制表示,主要运用位运算。

这里有一道例题:蓝书P639猛兽军团1 [SCOI2005]互不侵犯

题目:

  1. 题目描述
  2.  
  3. N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
  4.  
  5. 注:数据有加强(//)
  6. 输入输出格式
  7. 输入格式:
  8.  
  9. 只有一行,包含两个数NK <=N <=, <= K <= N * N
  10.  
  11. 输出格式:
  12.  
  13. 所得的方案数
  14.  
  15. 输入输出样例
  16. 输入样例#: 复制
  17.  
  18. 输出样例#: 复制

直接上代码,注释很详细

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<cstring>
  4. #define N 15
  5. #define M 110
  6. #define MAX 550
  7. using namespace std;
  8. /*
  9. 见蓝书641页
  10. */
  11. int s[MAX]; // 记录一行可能的状态
  12. int num[MAX]; //s数组对应每个状态放了多少个猛兽
  13. int states;
  14. long long f[N][M][MAX]; //f[i][j][k]第i行状态为k,放了j个猛兽
  15. int n,m;
  16. void init_state() //预处理s,num数组,代表一行之内所有的可能性
  17. {
  18. states = ;
  19. for(int i = ; i < ( << n); i++) //注意,这里是枚举状态
  20. {
  21. if(i & (i << )) //处理一排上的冲突情况
  22. continue;
  23. int t = i;
  24. num[states] = ;
  25. while(t)
  26. {
  27. num[states] += (t & );
  28. t = t >> ;
  29. }
  30. s[states++] = i; //保存状态
  31. }
  32. }
  33. void dp()
  34. {
  35. int a,c,mm,b,cc;
  36. long long ans;
  37. memset(f,,sizeof(f));
  38. //单独算第一行和最后一行
  39. for(int i = ; i < states; i++)
  40. {
  41. int j = num[i];
  42. if(j <= m) //不能超过总数
  43. f[][j][i]++;
  44. }
  45. for(int i = ; i < n; i++) //2~n - 1行
  46. {
  47. for(int j = ; j <= m; j++) // 到第i行,一共放了j个猛兽
  48. {
  49. for(a = ; a < states; a++) //i行状态
  50. {
  51. c = num[a];
  52. if(c > j)
  53. continue;
  54. mm = j - c;//前i - 1行的总数
  55. for(int b = ; b < states; b++) //枚举i-1行
  56. {
  57. cc = num[b];
  58. if(cc > mm)
  59. continue;
  60. if(s[a] & s[b]) //上下有攻击
  61. continue;
  62. if(s[a] & (s[b] << )) //对角有攻击
  63. continue;
  64. if(s[b] & s[a] << ) // 同上
  65. continue;
  66. f[i][j][a] += f[i - ][mm][b];
  67. }
  68. }
  69. }
  70. }
  71. ans = ;
  72. for(a = ; a < states; a++) //最后一行
  73. {
  74. c = num[a];
  75. if(c > m)
  76. continue;
  77. int j = m - c;
  78. for(int b = ; b < states; b++) //枚举n-1行
  79. {
  80. cc = num[b];
  81. if(cc > j)
  82. continue;
  83. if(s[a] & s[b]) //上下有攻击
  84. continue;
  85. if(s[a] & (s[b] << )) //对角有攻击
  86. continue;
  87. if(s[b] & s[a] << ) // 同上
  88. continue;
  89. f[n][m][a] += f[n - ][j][b];
  90. }
  91. ans += f[n][m][a];
  92. }
  93. printf("%lld\n",ans);
  94. }
  95. int main()
  96. {
  97. scanf("%d%d",&n,&m);
  98. init_state();
  99. dp();
  100. return ;
  101. }

上面这个代码过于复杂,不好理解,我们换一种写法:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int M=<<;
  4. long long g[M],h[M],f[][M][],n,k,tot=;
  5. int main()
  6. {
  7. cin>>n>>k;
  8. memset(f,,sizeof(f));
  9. for(int x=; x < (<<n); x++) //第一排单独处理
  10. {
  11. if(!(x & (x>>)) && !(x&(x<<)))g[x] = ;//处理g数组,同一排左右不矛盾
  12. int w = x;
  13. while(w)
  14. {
  15. if(w % )h[x]++;
  16. w /= ;
  17. }
  18. if(g[x])
  19. f[][x][h[x]] = ;
  20. }
  21. for(int x = ; x <= n; x++)
  22. {
  23. for(int y = ; y < (<<n); y++)
  24. {
  25. if(g[y])
  26. {
  27. for(int z = ; z < (<<n); z++)
  28. {
  29. if(g[z] && !(y&z) && !(y & (z>>)) && !(y&(z<<))) //只用考虑该排与上一排
  30. {
  31. for(int w = ; w + h[z] <= k; w++)
  32. f[x][z][w + h[z]] += f[x - ][y][w]; //w枚举总共放的国王的个数
  33. }
  34. }
  35. }
  36. }
  37. }
  38. for(int y=; y<(<<n); y++)tot+=f[n][y][k];
  39. cout<<tot;
  40. return ;
  41. }

动态规划---状压dp的更多相关文章

  1. 状态压缩动态规划 状压DP

    总述 状态压缩动态规划,就是我们俗称的状压DP,是利用计算机二进制的性质来描述状态的一种DP方式 很多棋盘问题都运用到了状压,同时,状压也很经常和BFS及DP连用,例题里会给出介绍 有了状态,DP就比 ...

  2. 状态压缩动态规划(状压DP)详解

    0 引子 不要999,也不要888,只要288,只要288,状压DP带回家.你买不了上当,买不了欺骗.它可以当搜索,也可以卡常数,还可以装B,方式多样,随心搭配,自由多变,一定符合你的口味! 在计算机 ...

  3. 动态规划专题(一)——状压DP

    前言 最近,决定好好恶补一下我最不擅长的\(DP\). 动态规划的种类还是很多的,我就从 状压\(DP\) 开始讲起吧. 简介 状压\(DP\)应该是一个比较玄学的东西. 由于它的时间复杂度是指数级的 ...

  4. 动态规划晋级——POJ 3254 Corn Fields【状压DP】

    转载请注明出处:http://blog.csdn.net/a1dark 分析:刚开始学状压DP比较困难.多看看就发现其实也没有想象中那么难.这道题由于列数较小.所以将行压缩成二进制来看.首先处理第一行 ...

  5. HDU5117 Fluorescent 期望 计数 状压dp 动态规划

    原文链接https://www.cnblogs.com/zhouzhendong/p/HDU5117.html 题目传送门 - HDU5117 题意 $T$ 组数据. 给你 $n$ 盏灯 ,$m$ 个 ...

  6. 动态规划:状压DP

    状压DP可以用在NP问题的小规模求解中(不理解,感觉和可以搜索的题很类似) 如果状态是个网格,数据范围很小,基本锁定状压DP 例题是BZOJ1725 题意是这样的,给定一个黑白图,然后种田,要求田与田 ...

  7. [bzoj1879][Sdoi2009]Bill的挑战_动态规划_状压dp

    Bill的挑战 bzoj-1879 Sdoi-2009 题目大意: 注释:$1\le t \le 5$,$1\le m \le 15$,$1\le length \le 50$. 想法: 又是一个看数 ...

  8. [bzoj3717][PA2014]Pakowanie_动态规划_状压dp

    Pakowanie bzoj-3717 PA-2014 题目大意:给你n个物品m个包,物品有体积包有容量,问装下这些物品最少用几个包. 注释:$1\le n\le 24$,$1\le m\le 100 ...

  9. 【状压DP】bzoj1087 互不侵犯king

    一.题目 Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上.下.左.右,以及左上.左下.右上.右下八个方向上附近的各一个格子,共8个格子. I ...

随机推荐

  1. Java_Web三大框架之Hibernate+jsp+HQL分页查询

    分页查询无处不在.使用Hibernate+jsp+HQL进行分页查询. 第一步:编写房屋实体类和House.hbm.xml映射. /* * 房屋实体类 */ public class House { ...

  2. Java中Math对象的属性与方法

    Math.sqrt() ——————>计算平方根Math.cbrt()————————>计算立方根Math.pow(a, b)——————————>计算a的b次方Math.max( ...

  3. [测试工具]----iperf

    iperf https://sourceforge.net/projects/iperf/ http://downloads.es.net/pub/iperf/ https://github.com/ ...

  4. C# Thu Mar 1 00:00:00 UTC+0800 2012 如何转换为2012-03-01

    string s = "Thu Mar 1 00:00:00 UTC+0800 2012"; DateTime dt = DateTime.ParseExact(s, " ...

  5. enote笔记语言(3)

    what&why(why not)&how&when&where&which:紫色,象征着神秘而又潜蕴着强大的力量,故取紫色. key&key-memo ...

  6. 洛谷——P1196 [NOI2002]银河英雄传说

    P1196 [NOI2002]银河英雄传说 题目大意: 给你一个序列,支持两种操作: 合并指令为$M_{i,j}$j​,含义为第i号战舰所在的整个战舰队列,作为一个整体(头在前尾在后)接至第j号战舰所 ...

  7. Selenium的安装和简单实用——PhantomJS安装

    简介 Selenium是一个用于Web应用程序测试的工具. Selenium测试直接运行在浏览器中,就像真正的用户在操作一样.支持的浏览器包括IE(7, 8, 9, 10, 11),Firefox,S ...

  8. HDU 1836 畅通工程

    畅通工程 Time Limit: 1000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 18636 ...

  9. POJ 1376 Robot

    Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 7866   Accepted: 2586 Description The R ...

  10. cogs 1310. [HAOI2006]聪明的猴子

    1310. [HAOI2006]聪明的猴子 ★   输入文件:monkey.in   输出文件:monkey.out   简单对比时间限制:1 s   内存限制:128 MB [题目描述] 在一个热带 ...