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

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

题目:

题目描述

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

注:数据有加强(//)
输入输出格式
输入格式: 只有一行,包含两个数N,K ( <=N <=, <= K <= N * N) 输出格式: 所得的方案数 输入输出样例
输入样例#: 复制 输出样例#: 复制

直接上代码,注释很详细

#include<cstdio>
#include<iostream>
#include<cstring>
#define N 15
#define M 110
#define MAX 550
using namespace std;
/*
见蓝书641页
*/
int s[MAX]; // 记录一行可能的状态
int num[MAX]; //s数组对应每个状态放了多少个猛兽
int states;
long long f[N][M][MAX]; //f[i][j][k]第i行状态为k,放了j个猛兽
int n,m;
void init_state() //预处理s,num数组,代表一行之内所有的可能性
{
states = ;
for(int i = ; i < ( << n); i++) //注意,这里是枚举状态
{
if(i & (i << )) //处理一排上的冲突情况
continue;
int t = i;
num[states] = ;
while(t)
{
num[states] += (t & );
t = t >> ;
}
s[states++] = i; //保存状态
}
}
void dp()
{
int a,c,mm,b,cc;
long long ans;
memset(f,,sizeof(f));
//单独算第一行和最后一行
for(int i = ; i < states; i++)
{
int j = num[i];
if(j <= m) //不能超过总数
f[][j][i]++;
}
for(int i = ; i < n; i++) //2~n - 1行
{
for(int j = ; j <= m; j++) // 到第i行,一共放了j个猛兽
{
for(a = ; a < states; a++) //i行状态
{
c = num[a];
if(c > j)
continue;
mm = j - c;//前i - 1行的总数
for(int b = ; b < states; b++) //枚举i-1行
{
cc = num[b];
if(cc > mm)
continue;
if(s[a] & s[b]) //上下有攻击
continue;
if(s[a] & (s[b] << )) //对角有攻击
continue;
if(s[b] & s[a] << ) // 同上
continue;
f[i][j][a] += f[i - ][mm][b];
}
}
}
}
ans = ;
for(a = ; a < states; a++) //最后一行
{
c = num[a];
if(c > m)
continue;
int j = m - c;
for(int b = ; b < states; b++) //枚举n-1行
{
cc = num[b];
if(cc > j)
continue;
if(s[a] & s[b]) //上下有攻击
continue;
if(s[a] & (s[b] << )) //对角有攻击
continue;
if(s[b] & s[a] << ) // 同上
continue;
f[n][m][a] += f[n - ][j][b];
}
ans += f[n][m][a];
}
printf("%lld\n",ans);
}
int main()
{
scanf("%d%d",&n,&m);
init_state();
dp();
return ;
}

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

#include<bits/stdc++.h>
using namespace std;
const int M=<<;
long long g[M],h[M],f[][M][],n,k,tot=;
int main()
{
cin>>n>>k;
memset(f,,sizeof(f));
for(int x=; x < (<<n); x++) //第一排单独处理
{
if(!(x & (x>>)) && !(x&(x<<)))g[x] = ;//处理g数组,同一排左右不矛盾
int w = x;
while(w)
{
if(w % )h[x]++;
w /= ;
}
if(g[x])
f[][x][h[x]] = ;
}
for(int x = ; x <= n; x++)
{
for(int y = ; y < (<<n); y++)
{
if(g[y])
{
for(int z = ; z < (<<n); z++)
{
if(g[z] && !(y&z) && !(y & (z>>)) && !(y&(z<<))) //只用考虑该排与上一排
{
for(int w = ; w + h[z] <= k; w++)
f[x][z][w + h[z]] += f[x - ][y][w]; //w枚举总共放的国王的个数
}
}
}
}
}
for(int y=; y<(<<n); y++)tot+=f[n][y][k];
cout<<tot;
return ;
}

动态规划---状压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】【28】Map遍历

    Map遍历 map的遍历一般有几种吧 遍历entrySet for(Map.Entry<String,String> entry : map.entrySet()){ } Iterator ...

  2. tidyverse生态链

    一套完整的数据分析流程 , 如下图所示 从图中可以看到,整个流程包括读取数据,整洁数据,数据探索和交流部分.经过前两部分, 我们可以得到一个整理好的数据,它的每一行都是一个样本 , 每一列是一个变量. ...

  3. 想学Python?这里有一个最全面的职位分析

    Python从2015年开始,一直处于火爆的趋势,目前Python工程师超越Java.Web前端等岗位,起薪在15K左右,目前不管是小公司还是知名大公司都在热招中. 当然,每个城市对岗位的需求也不尽相 ...

  4. 为什么Java中的密码优先使用 char[] 而不是String?

    可以看下壁虎的回答:https://www.zhihu.com/question/36734157 String是常量(即创建之后就无法更改),会保存到常量池中,如果有其他进程可以dump这个进程的内 ...

  5. 有赞 MySQL 自动化运维之路 — ZanDB

    转自:https://tech.youzan.com/youzan-mysql-auto-ops-road/ 一.前言 在互联网时代,业务规模常常出现爆发式的增长.快速的实例交付,数据库优化以及备份管 ...

  6. 阅读《JavaScript设计模式》第三章心得

    简单工厂模式 1.通过类实例化对象创建 传统的用面向对象方法去创建很多类去实现某些功能不妥当,这样不仅占用的很多类名称,而且别人使用这些方法的同时要记住每个类的名字,所以这样不适合团队开发,所以我们可 ...

  7. NOIp知识点复习——最短路计数

    $Mingqi\_H$ NOIp 2017考挂了...gg 重新开始好了. 计划明年2月24号前复习完所有的NOIp知识点(毕竟很不熟练啊),之后到七月底前学习完省选的东西(flag?). 从现在开始 ...

  8. [luogu1485 HNOI2009] 有趣的数列 (组合数学 卡特兰数)

    传送门 Solution 卡特兰数 排队问题的简单变化 答案为\(C_{2n}^n \pmod p\) 由于没有逆元,只好用分解质因数,易证可以整除 Code //By Menteur_Hxy #in ...

  9. 00.用 yield 实现 Python 协程

    来源:Python与数据分析 链接: https://mp.weixin.qq.com/s/GrU6C-x4K0WBNPYNJBCrMw 什么是协程 引用官方的说法: 协程是一种用户态的轻量级线程,协 ...

  10. Thesis Viva checklist

    This list gives you suggestions helpful in preparing to defend your thesis: I know my thesis thoroug ...