BZOJ 1087 互不侵犯king
Description
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
Input
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
Output
方案数。
Sample Input
3 2
Sample Output
16
首先这道题用到了名叫状压dp的算法
首先声明:这篇博客不适用于大神们!!!!!
看到互不侵犯的king这道题首先想到的是八皇后问题,但是发现和八皇后大不一样,因为八皇后是用的深搜的方法,但是由于根据国象的规则,一个棋盘能放的皇后要比国王少得多,所以DFS即可。
所以我们考虑其他的方法,因为国王的攻击范围很小,只有周围的一圈。但我们依然不能把所有的状态推出来(即使n<=9)。但我们可以发现只要确定了第一行,就可以将下面的用动规推出来。这样我们就可以用枚举的方式来做了。在枚举的同时,我们可以用二进制的方式来表示状态,这样较好比较,同时也可以压缩状态,这就是状压dp的思想。在这里可以模拟一下。
比如说n=5。 用1表示该格有国王,0反之。
1 1 1 1 1 这种情况显然是不存在的,我么就要把它排除掉。那么怎么排除呢?我们考虑用位运算的思想。将它 右移(>>)一位(因为国王的攻击范围只有1)。即 1 1 1 1 1再进行(&)运算,这样的返回值是1则出现冲突,再比如这种情况 1 0 1 0 1 1 1 1 1 1 。 1 0 1 0 1 这样的返回值是0,所以这种情况存在。而二进制我们可以直接用一个十进制数来表示。如 1 1 1 1 1 十进制是31,可以试一试计算 31&(31>>1)==1.而 1 0 1 0 1 十进制是21,
21&(21>>1)==0。比较时应该左移、右移都进行。另外我们还可以进行预处理。总状态数为 2^n-1,只进行循环即可,代码如下
int check2(int a)//一行自比
{
if(a&(a<<)) return ;
if(a&(a>>)) return ;
return ;
}
int get(int x)//计算状态为x,其中 1 的个数。
{
int tot=;
while(x){
if(x&)
tot++;
x=x>>;
}
return tot;
}int tot=(<<n)-;
for(int i=;i<=tot;i++)
if(check2(i)){
zt[++num]=i;//状态
gs[num]=get(i);//该状态含的国王的个数
}
接下来讲dp的过程——
int f[10] (i) [600] (j) [82] (k) {0};//i为行数,j为第j种状态,k为当前总国王数 f[i][j][k]表示第i行状态为第j种放置了k个国王的方案数。
另外的一种预处理如下,对比两行的状态,可以加速dp过程中的比较。
int check1(int a,int b)//两行对比
{
if(a&(b<<)) return ;
if(a&(b>>)) return ;
if(a&b)return ;//对比两行时就需要对比不移动时的状态,至于为什么,自行脑补
return ;
}
for(int i=;i<=num;i++)//pd[i][j]==1则表示i在上一行j在下一行,并且不冲突
for(int j=;j<=num;j++)
if(check1(zt[i],zt[j]))
pd[i][j]=pd[j][i]=;
主要的dp过程如下
for(int i=;i<n;i++)//循环行数,对应f数组中的行数(i)
for(int j=;j<=num;j++)//循环状态,对应f数组中的(j)
for(int k=;k<=m;k++)//循环国王数,对应数组中的(k)
if(f[i][j][k])
for(int q=;q<=num;q++)//循环i下一行的状态
if(pd[j][q]&&(k+gs[q]<=m))//满足条件就继续
f[i+][q][k+gs[q]]+=f[i][j][k];
long long int ans=;
for(int i=;i<=num;i++)//把第n行的所有状态的f值相加即为答案
ans+=f[n][i][m];
这就是主要的函数,其他的自己加上的吧,光复制标程是没有意义的!!
注意:f[0][1][0]=1 即初始的状态。
BZOJ 1087 互不侵犯king的更多相关文章
- BZOJ 1087 互不侵犯King 状态压缩DP
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1087 题目大意; 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国 ...
- BZOJ 1087 互不侵犯King (位运算)
题解:首先,这道题可以用位运算来表示每一行的状态,同八皇后的搜索方法,然后对于限制条件不相互攻击,则只需将新加入的一行左右移动与上一行相&,若是0则互不攻击,方案可行.对于每种方案,则用递推来 ...
- BZOJ 1087 互不侵犯
Description 在\(N \times N\)的棋盘里面放\(K\)个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共\(8 ...
- BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3336 Solved: 1936[Submit][ ...
- bzoj 1087 [SCOI2005]互不侵犯King 状态压缩dp
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MB[Submit][Status][Discuss] Descripti ...
- BZOJ 1087:[SCOI2005]互不侵犯King(状压DP)
[SCOI2005]互不侵犯King [题目描述] 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子 ...
- 1087: [SCOI2005]互不侵犯King
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4276 Solved: 2471[Submit][ ...
- 【状压dp】互不侵犯KING
互不侵犯KING Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3866 Solved: 2264[Submit][Status][Discuss] ...
- BZOJ-1087 互不侵犯King 状压DP+DFS预处理
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MB Submit: 2337 Solved: 1366 [Submit][ ...
随机推荐
- Performing a full database disaster recovery with RMAN
Performing a full database disaster recovery with RMAN1. Make the RMAN backup set pieces available.2 ...
- UVA 1374 Power Calculus
题意: 给出m,问对n最少进行几次操作.n初始为1,能得到m.操作1位将n平方.操作2为将n除以之前出现的n值中的任意一个. 分析: 其实是关于指数的操作,即从1到m最少的步数.我们可以先确定最少步数 ...
- sublime text 2中Windows下编写的脚本在Linux平台上运行遇到字符问题
今天在windows下的sublime text 2下写了个脚本,上传到ubuntu服务器中执行后提示: -bash: /usr/bin/python: /usr/bin/python^M: bad ...
- Android Studio 没有assets目录的问题
Where to place the assets folder in Android Studio If you are having problems with asset files not ...
- 关于 java.io.IOException: open failed: EACCES (Permission denied)
今天解决了一个问题,不得不来和大家分享.就是关于 java.io.IOException: open failed: EACCES (Permission denied)的问题,网上也有很多人把这个问 ...
- MySQL的三层架构之一----连接层
1.mysql的服务端可以分为三层,分别是连接层,SQL层,存储层. 2.架构图 3.连接层定义了通信server端与client协议:
- SPI模式下MCU对SD卡的控制及操作命令
一.前言 SD 卡有两个可选的通讯协议:SD 模式和 SPI模式 SD 模式是SD 卡标准的读写方式,但是在选用SD 模式时,往往需要选择带有SD 卡控制器接口的 MCU,或者必须加入额外的SD卡控制 ...
- java--工具方法
根据时间戳得到具体的时间: public static void main(String[] args) { SimpleDateFormat sdf = new SimpleDateFormat(& ...
- Linux下利用fork()创建子进程并使父进程等待子进程结束
int status; pid_t t = fork(); if(t){ waitpid(t, &status, 0); }else{ system("vi temp ...
- ecshop的模板文件中如何判断用户是否登录
ecshop中对于smarty的运用和改造有很大的值得借鉴的地方,在dwt模板文件中可以直接判断用户是否登录,现在有规定,凡是只展示不销售的电商平台,一律不得展示商品价格,但可以在用户登录后显示. & ...
