kings(骑士)解题报告
kings(骑士)
Time Limit5000 ms Memory Limit131072 KBytes
Description
用字符矩阵来表示一个8x8的棋盘,'.'表示是空格,'P'表示人质,'K'表示骑士。 每一步,骑士可以移动到他周围的8个方格中的任意一格。如果你移动到的格子中有人质(即'P'),你将俘获他。但不能移到出棋盘或当前是'K'的格子中。 请问最少要移动多少步骑士才能俘获所有的人质。
Input Format
第一行一个整数N(<=5),表示有多少个棋盘。即多组测试数据。 每一组有8行,每行8个字符。字符只有'.',大写'P',大写'K'三种字符。'P'和'K'的个数范围都在[1,10]。
Output Format
有N行,每行只一个整数,相应棋盘俘获全部人质所需要的最少步数。
Sample Input
2
P......P
........
........
........
...KK...
........
........
P......P
.....P.P
..K....P
....K...
..PP...P
...K..KK
........
K.......
KP.K....
Sample Output
20
9
Solution
分析:1.p,k<=10考虑用状压
2.每个骑士的路径独立互不影响(若路径相交必然不是最优解)
基于以上两点,可以先求出每个骑士拯救集合S(状压2进制表示)的最小步数,然后通过这个求出前i个骑士拯救集合S的最小步数
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 0x7f7f7f7f
using namespace std; int T,p[],k[],d[][];
int f1[][][<<],f2[][<<]; void ycl(){
for (int xa=;xa<=;++xa)
for (int ya=;ya<=;++ya)
for (int xb=;xb<=;++xb)
for (int yb=;yb<=;++yb){
int x=(xa-)*+ya,y=(xb-)*+yb;
int dex=abs(xa-xb),dey=abs(ya-yb);
int t=min(dex,dey);
d[x][y]=t+(dex-t)+(dey-t);
}
} int main(){
ycl();
for (scanf("%d",&T);T;--T){
memset(f1,0x7f,sizeof f1);
memset(f2,0x7f,sizeof f2);
p[]=k[]=;
for (int i=;i<=;++i)
for (int j=;j<=;++j){
char c=getchar();
while (c!='.'&&c!='P'&&c!='K') c=getchar();
if (c=='P') p[++p[]]=(i-)*+j;
if (c=='K') k[++k[]]=(i-)*+j;
}
for (int i=;i<=k[];++i){
for (int j=;j<=p[];++j)
f1[i][j][<<(j-)]=d[k[i]][p[j]];
for (int s=;s<(<<p[]);++s)
for (int j=;j<=p[];++j)
if (s&(<<(j-)))
for (int l=;l<=p[];++l)
if (!(s&(<<(l-))))
f1[i][l][s|(<<(l-))]=min(f1[i][l][s|(<<(l-))],f1[i][j][s]+d[p[j]][p[l]]);
}
for (int i=;i<=k[];++i)
for (int s=;s<(<<p[]);++s)
for (int j=;j<=p[];++j)
f1[i][][s]=min(f1[i][][s],f1[i][j][s]);
f2[][]=;
for (int i=;i<=k[];++i){
f2[i][]=;
for (int s=;s<(<<p[]);++s){
f2[i][s]=f2[i-][s];
for (int ss=;ss<s;++ss)
if ((s|ss)==s&&(f2[i-][ss]!=INF&&f1[i][][s^ss]!=INF))
f2[i][s]=std::min(f2[i][s],f2[i-][ss]+f1[i][][s^ss]);
}
}
printf("%d\n",f2[k[]][(<<p[])-]);
}
}
以上是标解,下面提供一种(蒟蒻)的做法
我们发现每个骑士只有两种状态:1.在初始位置 2.在某个人质的位置上
每个人质有三种状态:1.没被拯救 2.已经被拯救 3.被拯救且有骑士在这个位置
所以 用f[s1][s2]表示人质状态为s1,骑士的状态为s2的最少步数
每次转移可以将s1中的骑士走出去拯救人质或将s2中在初始位置的骑士走出去拯救人质
#include<cstdio>
#include<cstring>
#include<algorithm> short int o3[][];
short int p[],k[];
short int T,A,B,ans,pw[],d[][],f[<<][]; inline void dfs(int s1,int s2){
if (f[s1][s2]+(p[]-o3[][s2]-o3[][s2])>=ans) return;
if (o3[][s2]+o3[][s2]==p[]){
ans=std::min(ans,f[s1][s2]);
return;
}
for (int i=;i<p[];++i)
if (!((s2/pw[i])%)){
for (int j=;j<p[];++j)
if (((s2/pw[j])%)==){
int t1=s1,t2=s2-pw[j]+pw[i]*;
if (f[t1][t2]>f[s1][s2]+d[p[j+]][p[i+]])
f[t1][t2]=f[s1][s2]+d[p[j+]][p[i+]],dfs(t1,t2);;
}
for (int j=;j<k[];++j)
if (s1&(<<j)){
int t1=s1^(<<j),t2=s2+pw[i]*;
if (f[t1][t2]>f[s1][s2]+d[k[j+]][p[i+]])
f[t1][t2]=f[s1][s2]+d[k[j+]][p[i+]],dfs(t1,t2);
}
}
} inline void csh(){
memset(f,0x7f,sizeof f);
p[]=k[]=;
for (int i=;i<=;++i)
for (int j=;j<=;++j){
char c=getchar();
while (c!='.'&&c!='P'&&c!='K') c=getchar();
if (c=='P') p[++p[]]=(i-)*+j;
if (c=='K') k[++k[]]=(i-)*+j;
}
A=(<<(k[]))-;
f[A][]=;
ans=d[k[]][p[]];
for (int i=;i<=p[];++i) ans+=d[p[i-]][p[i]];
} inline void ycl(){
for (int xa=;xa<=;++xa)
for (int ya=;ya<=;++ya)
for (int xb=;xb<=;++xb)
for (int yb=;yb<=;++yb){
int x=(xa-)*+ya,y=(xb-)*+yb,t;
int dex=std::abs(xa-xb),dey=std::abs(ya-yb);
t=std::min(dex,dey);
d[x][y]=d[y][x]=t+(dex-t)+(dey-t);
}
int maxs=;
for(int i=;i<;++i) maxs+=pw[i]*;
for (int i=;i<=maxs;++i)
for (int j=;j<;++j)
if ((i/pw[j])%)
++o3[(i/pw[j])%-][i];
} int main(){
pw[]=;
for (int i=;i<;++i) pw[i]=pw[i-]*;
ycl();
for (scanf("%d",&T);T;--T){
csh();
dfs(A,);
printf("%d\n",ans);
}
}
kings(骑士)解题报告的更多相关文章
- 洛谷 P2607 [ZJOI2008]骑士 解题报告
P2607 [ZJOI2008]骑士 题目描述 Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬. 最近发生了一件可怕的事情,邪恶的Y国发动了一 ...
- [BZOJ1040] [ZJOI2008]骑士 解题报告
Description Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战火 ...
- CH Round #56 - 国庆节欢乐赛解题报告
最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧. T1 魔幻森林 描述 Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树 ...
- 二模13day1解题报告
二模13day1解题报告 T1.发射站(station) N个发射站,每个发射站有高度hi,发射信号强度vi,每个发射站的信号只会被左和右第一个比他高的收到.现在求收到信号最强的发射站. 我用了时间复 ...
- BZOJ 1051 最受欢迎的牛 解题报告
题目直接摆在这里! 1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4438 Solved: 2353[S ...
- 习题:codevs 2822 爱在心中 解题报告
这次的解题报告是有关tarjan算法的一道思维量比较大的题目(真的是原创文章,希望管理员不要再把文章移出首页). 这道题蒟蒻以前做过,但是今天由于要复习tarjan算法,于是就看到codevs分类强联 ...
- 习题:codevs 1035 火车停留解题报告
本蒟蒻又来写解题报告了.这次的题目是codevs 1035 火车停留. 题目大意就是给m个火车的到达时间.停留时间和车载货物的价值,车站有n个车道,而火车停留一次车站就会从车载货物价值中获得1%的利润 ...
- 习题: codevs 2492 上帝造题的七分钟2 解题报告
这道题是受到大犇MagHSK的启发我才得以想出来的,蒟蒻觉得自己的代码跟MagHSK大犇的代码完全比不上,所以这里蒟蒻就套用了MagHSK大犇的代码(大家可以关注下我的博客,友情链接就是大犇MagHS ...
- 习题:codevs 1519 过路费 解题报告
今天拿了这道题目练练手,感觉自己代码能力又增强了不少: 我的思路跟别人可能不一样. 首先我们很容易就能看出,我们需要的边就是最小生成树算法kruskal算法求出来的边,其余的边都可以删掉,于是就有了这 ...
随机推荐
- C# vb .net实现翻转特效滤镜
在.net中,如何简单快捷地实现Photoshop滤镜组中的翻转特效效果呢?答案是调用SharpImage!专业图像特效滤镜和合成类库.下面开始演示关键代码,您也可以在文末下载全部源码: 设置授权 第 ...
- 数组中[::-1]或[::-n]的区别,如三维数组[:,::-1,:]
import numpy as npa=np.array([[11,12,13,14,15,16,17,18],[21,22,23,24,25,26,27,28],[31,32,33,34,35,36 ...
- docker安装mysql笔记
首先 查找镜像 docker search mysql 拉取镜像 : docker pull mysql 拉取成功后,查看本地镜像: docker images 可以看到本地有两个镜像(redis是我 ...
- 【转载】PC端微信设置操作快捷键方法
在电脑上使用微信的时候,有时候我们需要自定义PC版微信快捷键操作,支持自定义微信快捷键设置的有:发送消息快捷键.截屏快捷键.打开微信快捷键以及检测快捷键热键是否与其他软件设置冲突.并且自定义设置PC微 ...
- Node.js 项目中解决 SQL 注入和 XSS 攻击
1.SQL 注入 SQL 注入,一般是通过把 SQL 命令插入到 Web 表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的 SQL 命令. SQL 注入示例 在登录界面,后端会根 ...
- WPF 依赖属性前言
WPF 依赖属性前言 在.net中,我们可以属性来获取或设置字段的值,不需要在编写额外的get和set方法,但这有一个前提,那就是需要在对象中拥有一个字段,才能在此字段的基础上获取或设置字段的值, ...
- secureCRT 中各种传输协议分析 启动daemon运行守护进程(转)
转载链接:http://blog.sina.com.cn/s/blog_61798d5d01018yk4.html [Telnet]著名的终端访问协议,传统的网络服务程序,如FTP.POP和Telne ...
- 使用Cloudera Manager添加Sentry服务
使用Cloudera Manager添加Sentry服务 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.通过CM添加Sentry服务 1>.点击添加服务进入CM服务安装向 ...
- openssl获取ssl证书,配置https
- pipy配置镜像源
新电脑第一次使用使用pip命令下载贼慢 我们需要使用国内pipy镜像,参考如下 https://mirrors.tuna.tsinghua.edu.cn/help/pypi/ 所以只要设置一下就行了: ...