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. Mac开发中遇到的一些小问题解析

    通过mac开发的过程中,有一些小问题出现,列如下,后续会持续增加: 1. 命令行清空废纸篓(jar包太多,倾倒废纸篓太慢) sudo rm -rfv ~/.Trash /Volumes/*/.Tras ...

  2. git merge的使用

    在实际开发中经常会用到git merge操作.但很多情况下我们并不想合并后直接提交,这里介绍git merge的两个常用参数: --no-commit --no-commit 参数使得合并后,为了防止 ...

  3. Linux 定时清除日志 Log

    一.原因 写这篇的原因是项目中log没有定时清除,服务器上项目是用脚本启动,log文件只会在启动时生成一次,这时,由于项目在不断运行中,导致log越来越大.如果删除log文件,还得把项目停掉在启动,这 ...

  4. git更新远程仓库报错

    hint: Updates were rejected because the tip of your current branch is behind hint: its remote counte ...

  5. Vue Router的入门以及简单使用

    Vue Router 是Vue官方的路由管理器,是Vue用来实现SPA的插件.它和 Vue.js 的核心深度集成,让构建单页面应用(SPA)变得易如反掌. 基本概念: 路由:是一种映射关系,是 “pa ...

  6. JavaWeb基础—VerifyCode源码

    package com.jiangbei.verifycodeutils; import java.awt.BasicStroke; import java.awt.Color; import jav ...

  7. JS 判断滚动底部并加载更多效果。。。。。。。。。

    JS 判断滚动底部并加载更多效果......... <html lang="zh-cn"> <head> <meta http-equiv=" ...

  8. 「PKUSC2018」真实排名

    题面 题解 因为操作为将一些数字翻倍, 所以对于一个数\(x\), 能影响它的排名的的只有满足\(2y\geq x\)或\(2x>y\)的\(y\) 将选手的成绩排序,然后考虑当前点的方案 1. ...

  9. 我用 Python 爬取微信好友,最后发现一个大秘密

    前言 你身处的环境是什么样,你就会成为什么样的人.现在人们日常生活基本上离不开微信,但微信不单单是一个即时通讯软件,微信更像是虚拟的现实世界.你所处的朋友圈是怎么样,慢慢你的思想也会变的怎么样.最近在 ...

  10. Mkdir方法

    新建目录或文件夹. 语法 MkDir 路径 所需的_路径_参数是一个字符串表达式,标识的目录或文件夹创建. _路径_可以包含驱动器. 如果未指定驱动器, MkDir当前的驱动器上创建新目录或文件夹. ...