【状压DP】bzoj1087 互不侵犯king
一、题目
Description
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上、下、左、右,以及左上、左下、右上、右下八个方向上附近的各一个格子,共8个格子。
Input
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
Output
方案数
Sample Input
3 2
Sample Output
16
原题链接→_→bzoj1087: [SCOI2005]互不侵犯King
二、题目分析
其实我们可以用一张美妙的表来解决这道题(划掉)这道题我们首先考虑暴搜解决,然而似乎状态略多会炸……
搜索不行,我们很容易能想到DP,这里我们引入一个神奇的DP——状态压缩型动态规划。状态压缩是状压DP的核心(废话!),本人在上一篇blog中详细介绍了状态压缩的思想,诸位看官不妨移步一看,可能会对理解状压DP起到一定帮助(链接→_→【宽度优先搜索】神奇的状态压缩 CodeVs1004四子连棋)
对于每一行的状态,我们用1表示国王,0表示不放国王。由于每个位置只有0和1两种状态,我们可以使用位运算判断每行的状态是否合法。例如:10101010就是一种合法状态,而11111111就不合法。每行状态表示的十进制数就是我们压缩后的状态。
我们需要做两个预处理,先枚举每行所有可能的状态,记录下合法状态。然后判断两个状态是否能作为临行放置,并用布尔类型的二维数组存储其关系。
预处理之后,就是常规的DP,状态转移方程如下:
f[i][j][now]=∑f[i-1][j-num[now]][q]
略作说明:f[i][j][k]代表前i行,总共放j个国王,第i行状态为k时的方案数。状态转移方程中的num[now]代表状态为now的行中国王的数目,q表示第i-1行的状态。
三、代码实现
#include<stdio.h>
int n,k;
long long ans;
bool s[],map[][];//判断状态是否合法;判断两个状态是否能作为临行
int num[];//num[i]代表编号为i的状态含有的国王数
long long f[][][];
int sum;
void pre_s()//预处理s数组
{
int i;
for(i=;i<sum;++i)
{
if((i&(i<<))==)
{
s[i]=true;
int t=i,cnt=;
while(t)
{
cnt+=(t&);
t>>=;
}
num[i]=cnt;
f[][cnt][i]=;
}
}
}
void pre_map()//预处理map数组
{
int i,j;
for(i=;i<sum;++i)
{
if(!s[i])continue;
for(j=;j<sum;++j)
{
if(!s[j])continue;
if((!(i&j))&&(!((i<<)&j))&&(!((i>>)&j)))map[i][j]=true;
}
}
}
void dp()
{
int i,j,now;
for(i=;i<=n;++i)
for(j=;j<=k;++j)
for(now=;now<sum;++now)
{
if(!s[now])continue;
if(num[now]>j)continue;
int q;
for(q=;q<sum;q++)
{
if(!s[q])continue;
if(!map[now][q])continue;
if(num[q]+num[now]>j)continue;
f[i][j][now]+=f[i-][j-num[now]][q];
}
}
}
int main()
{
scanf("%d%d",&n,&k);
sum=<<n;
pre_s();
pre_map();
dp();
for(int i=;i<sum;++i)
{
if(!s[i])continue;
ans+=f[n][k][i];
}
printf("%lld",ans);
return ;
}
bzoj1087 互不侵犯king
弱弱地说一句,本蒟蒻码字也不容易,转载请注明出处http://www.cnblogs.com/Maki-Nishikino/p/5992703.html
【状压DP】bzoj1087 互不侵犯king的更多相关文章
- 【状压dp】互不侵犯KING
互不侵犯KING Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3866 Solved: 2264[Submit][Status][Discuss] ...
- 状压DP之互不侵犯
题目描述 这里 在\(N*N\) 的棋盘里面放\(k\)个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 输入格式 只有 ...
- BZOJ-1087 互不侵犯King 状压DP+DFS预处理
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MB Submit: 2337 Solved: 1366 [Submit][ ...
- bzoj1087 互不侵犯King 状压dp+bitset
题目传送门 题目大意:中文题面. 思路:又是格子,n又只有9,所以肯定是状压dp,很明显上面一行的摆放位置会影响下一行,所以先预处理出怎样的二进制摆放法可以放在上下相邻的两行,这里推荐使用bitset ...
- bzoj1087互不侵犯King(状压)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1087 简单的状压dp.但是wa了好几发.注意long long. 注意0和0的连边.而且不能 ...
- 刷题向》关于第一篇状压DP BZOJ1087 (EASY+)
这是本蒟蒻做的第一篇状压DP,有纪念意义. 这道题题目对状压DP十分友善,算是一道模板题. 分析题目,我们发现可以用0和1代表每一个格子的国王情况, 题目所说国王不能相邻放置,那么首先对于每一行是否合 ...
- bzoj1087互不侵犯King——状压DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1087 水题... 然而犯了两个致命小错误,调了好半天...详见注释. 代码如下: #incl ...
- 互不侵犯_状压$dp$
如果有想学习状压\(dp\)的童鞋,请光临博客状压\(dp\)初学 互不侵犯 题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八 ...
- BZOJ1087 SCOI2005 互不侵犯King 【状压DP】
BZOJ1087 SCOI2005 互不侵犯King Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附 ...
随机推荐
- charles抓包工具分享
今天,给大组内QA做了一次分享,主要面向移动端测试,介绍了我平时在测试工作中用到的功能,大家都积极响应,现场搭环境,现场操作,现场提问解答,最后大家都成功的利用起来了,感觉很有成就感.下面介绍我今天分 ...
- HP ALM 使用经验
使用HP ALM(Application Lifecycle Management)软件有一个多月的时间了,我是从安装,部署,建项,配置,使用,再到问题收集,这个过程过来的.发现ALM是一个功能确实强 ...
- ios - NSTimer中target的self是强引用问题
当控制器ViewController跳转进入控制器OneViewController中的时候开启定时器,让定时器每隔一段时间打印一次,当OneViewController dismiss的时候,控制器 ...
- OEIS A140358
以前也许做过? 有点方 最小整数1到k 加减得到 n 1+-2+-3+-...+-k = n 求最小k #include <cstdio> #include <algorithm&g ...
- poj 3190 Stall Reservations
http://poj.org/problem?id=3190 Stall Reservations Time Limit: 1000MS Memory Limit: 65536K Total Su ...
- $.Callbacks()
<script> var cb = $.Callbacks(); //Callbacks(option) 有4个参数,可以多个参数写一起,空格分隔开 //once 多个fire() 只触发 ...
- 使用Vue构建中(大)型应用
init 首先要起一个项目,推荐用vue-cli安装 $ npm install -g vue-cli $ vue init webpack demo $ cd demo $ npm install ...
- BufferedReader与Scanner的区别
在Java中,我们都知道Java的标准输入串是System.in.但是我们却很少在Java中看到谁使用它,这是因为我们平时输入的都是一个字符串或者是一个数字等等.而System.in提供的read方法 ...
- 【KeyCode 键码】
Key codes returned by Event.keyCode. These map directly to a physical key on the keyboard. KeyCode是由 ...
- Linux主机规划
当你想装linux操作系统的时候,一定要知道你的用途,不同的用途就要规划不同的装机方式. 首先要知道一些概念: 挂载:利用一个目录当成进入点,将磁盘分区的数据放置在该目录下. 磁盘第一个扇区记录的信息 ...