1896 [SCOI2005]互不侵犯King

【问题描述】在n*n(1<=n<=10)的棋盘上放k(0<=k<=n*n)个国王(可攻击相邻的8 个格子),求使它们无法互相攻击的方案总数。

【输入格式】输入有多组方案,每组数据只有一行为两个整数n和k。

【输出格式】每组数据一行为方案总数,若不能够放置则输出0。

【问题分析】

由问题很容易联想起经典的“八皇后”问题,似乎就是“皇后”变成了“国王”,而且格子范围似乎也差不多,所求问题也一样。那么这个问题也能用搜索解决吗?

可稍加分析可知搜索是很难胜任的,因为国王的数目可以是很大,加上它与“八皇后”问题的一个本质上的不同便是每个国王只影响周围的一个格子,所以剪枝条件也很少,指数级别的搜索是无法在时限内出解的。

那么一般的动态规划能解决吗?典型的二维DP,F[I,J]似乎无法很好地把状态表示出来,因此我们只能考虑状态压缩的动态规划。

首先我们要注意到这题的关键——每个国王只影响周围八个方向的一个格子,它虽然否定了搜索,却给状态压缩带来了无限生机!

我们改变之前动态规划的思维方式,一行一行地摆放国王,当我们摆放第I行时,这一行只会和前后一行的互相影响,而这一行的状态是可以由我们确定的。那是否可以把一行当作一个整体,然后像传统的动态规划那样进行处理呢?让我们试一下。

每一行它对下一行的影响就体现在这一行的摆放方式以及之前总共放了多少个国王。所以我们可以把摆放方式作为状态,设f[i,j,s]表示第i行状态为a[j]且前i行已放s个国王的方案总数。这样很容易便得到了一个粗略的方程:

 F[i,j,S]=∑F[i-1,k,T]

a[j],a[k]分别表示一种摆放方式,F[i,j]表示第i行用a[j]的摆放方式,且a[j]与a[k]相兼容。并且S等于T加上a[j]这种方式在这一行放置的国王数。

很明显这个方程是没有后效性的,可关键就在于j,k怎么在计算机上表示出来,这就需要我们的主题:状态压缩

看图便知,每一个格子只有两种状态,放和不放,并且注意到格子宽度最大为9。由这便想到了熟悉的二进制表示法。每一个格子对应一个二进制位。这样每一行便对应一个N位的二进制数,如下图所示:

1   0   0   0   1   0   0   0

即十进制的128+8=136

这样我们就可以把一种摆放方式转化为一个数,这样上面方程中的J,K就可以用数字来代替。我们就把一行的摆放方式作为状态,并把它压缩成了一个数!具体的算法流程如下:

①对于每一行,我们通过搜索得出一个合法状态。

②然后再枚举上一行与这一行相容的状态再累加即可,状态用N位的二进制数表示,最大仅为512,所以一个512*9*81的数组就可以了,还可以用滚动数组的技巧。空间是肯定可以承受的。

而一个粗略的时间复杂度:O(K*N*2^N*2^N),似乎大了点。不过注意到由于国王是不能相邻放置的。所以我们可以用一个f(n)来表示当列数为n时每一行可能的放置总数。则f(n)=f(n-1)+f(n-2)初始值:f(1)=2,f(2)=3。

则f(9)=89。因此最大也才是9*89*89*81≈6000000。是可以承受的。

压缩行,有king是1,没有是0.
判断可行,就是将上一行与这一行按位与,接着左移,右移。
剩下的就是简单的dp了。

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=;
int n,k,a[],b[],tp;
long long f[N][N*N][<<N],ans;
//第i行,一共摆放了j个king,第i行的摆放情况是g
void dfs(int num,int lst,int at,int bt)
{
if(num==n)
{
++tp;
a[tp]=at;
b[tp]=bt;
return ;
}
dfs(num+,lst,at,bt);
if(num-lst>=)
{
at|=(<<num);
bt++;
dfs(num+,num,at,bt);
}
}
int main()
{
scanf("%d%d",&n,&k);
dfs(,-,,);
f[][][]=;
int end=(<<n)-;
for(int i=;i<=n;i++)
for(int j=;j<=k;j++)
for(int g=;g<=end;g++)
if(f[i-][j][g]>)
for(int h=;h<=tp;h++)
if((a[h]&g)==&&(a[h]&(g<<))==&&(a[h]&(g>>))==&&j+b[h]<=k)
f[i][j+b[h]][a[h]]+=f[i-][j][g];
for(int i=;i<=end;i++)
ans+=f[n][k][i];
printf("%lld\n",ans);
return ;
}

SGU 223 little kings BSOJ2772 状压DP的更多相关文章

  1. SGU 223 Little Kings(状压DP)

    Description 用字符矩阵来表示一个8x8的棋盘,'.'表示是空格,'P'表示人质,'K'表示骑士.每一步,骑士可以移动到他周围的8个方格中的任意一格.如果你移动到的格子中有人质(即'P'), ...

  2. Kings(状压DP)

    Description 用字符矩阵来表示一个8x8的棋盘,'.'表示是空格,'P'表示人质,'K'表示骑士.每一步,骑士可以移动到他周围的8个方格中的任意一格.如果你移动到的格子中有人质(即'P'), ...

  3. SGU 132. Another Chocolate Maniac 状压dp 难度:1

    132. Another Chocolate Maniac time limit per test: 0.25 sec. memory limit per test: 4096 KB Bob real ...

  4. [SGU223]Little Kings(状压DP)

    随便DP一下 Code #include <cstdio> int sta[150],cnt[150],tp,n,k; long long dp[12][144][150],Ans; in ...

  5. 状压DP SGU 223 Little Kings

    题目传送门 /* 题意:n*n的矩阵,放置k个king,要求king互相不能攻击,即一个king的8个方向都没有另外的king,求方案个数 状态压缩DP:dp[i][num[j]][s] 代表在第i行 ...

  6. BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]

    1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3336  Solved: 1936[Submit][ ...

  7. nefu1109 游戏争霸赛(状压dp)

    题目链接:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1109 //我们校赛的一个题,状压dp,还在的人用1表示,被淘汰 ...

  8. poj3311 TSP经典状压dp(Traveling Saleman Problem)

    题目链接:http://poj.org/problem?id=3311 题意:一个人到一些地方送披萨,要求找到一条路径能够遍历每一个城市后返回出发点,并且路径距离最短.最后输出最短距离即可.注意:每一 ...

  9. [NOIP2016]愤怒的小鸟 D2 T3 状压DP

    [NOIP2016]愤怒的小鸟 D2 T3 Description Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0,0)处,每次Kiana可 ...

随机推荐

  1. 关于mysql-mybatis批量添加

    mybatis怎么实现一次插入多条数据   以后从新浪博客转到博客园这边来记录把.   这篇地址:http://blog.sina.com.cn/s/blog_13e9702640102ysho.ht ...

  2. pwd的实现20155301

    pwd的实现 任务要求: 1) 学习pwd命令 2) 研究pwd实现需要的系统调用(man -k; grep),写出伪代码 3) 实现mypwd 4) 测试mypwd 实现过程 1)首先查看是否有有用 ...

  3. 20145234黄斐《Java程序设计》实验五—网络安全与编程

    1: 两人一组结对编程: 0. 参考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA 1. 结对实现中缀表达式转后缀表达式的功能 MyBC.jav ...

  4. 学习和使用STL

    STL是一个标准规范,它只是为容器.迭代器和泛型算法等组件定义了一整套统一的上层访问接口及各种组件之间搭配运用的一般规则,而没有定义组件底层的具体实现方法. STL主要包括下面这些组件:I/O流,st ...

  5. P4360 [CEOI2004]锯木厂选址

    P4360 [CEOI2004]锯木厂选址 这™连dp都不是 \(f_i\)表示第二个锯木厂设在\(i\)的最小代价 枚举1号锯木厂 \(f_i=min_{0<=j<i}(\sum_{i= ...

  6. GNS3 jungle newsfeed 隐藏

    windows 7 windows 8.1 1.开始---运行 输入(没有引号):“%appdata%” 2.修改---GNS3/gns3_gui.ini 的两行参数 "default_lo ...

  7. 【免费培训】腾讯WeTest&TesterHome WorkShop | 一起学压测

    2019年,中国移动软件市场仍呈现快速增长趋势,移动新生态孕育而生.而移动软件质量问题越发受到用户的关注,成为用户体验的关键因素.目前移动软件测试人才稀缺,而性能测试作为一项高门槛.高技术的测试能力, ...

  8. JDBC Mysql 驱动连接异常

    在做JDBC连接Mysql的时候遇到了三个异常: 第一个是:mysql8.0 caching_sha2_password 这个异常是由于是因为在mysql8.0之前的密码规则是mysql_native ...

  9. Java线程wait和sleep的区别

    Java中调用wait方法或者sleep方法都可以让线程进入waitint或者time-waiting状态,但是它们还是 有所不同的: wait是Object中的方法,而sleep则是Thread中的 ...

  10. java多线程相关代码

    1.创建线程的三种方式 使用Thread package com.wpbxx.test; //1.自定义一个类,继承java.lang包下的Thread类 class MyThread extends ...