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!专业图像特效滤镜和合成类库.下面开始演示关键代码,您也可以在文末下载全部源码: 设置授权 第一步 ...
- Spring通过注解@Autowired/@Resource获取bean实例时为什么可以直接获取接口而不是注入的类
问: 这个问题困扰了我好久,一直疑问这个接口的bean是怎么注入进去的?因为只看到使用@Service注入了实现类serviceImpl,使用时怎么却获取的接口,而且还能调用到实现类的方法,难道这个接 ...
- js函数(续)
一.全局变量和局部变量全局变量:当前js页面中均可使用的变量[声明在函数外面的变量],整个js页面中均可以使用.局部变量:声明在函数内部的变量,只能在函数内部使用.eg: var a = 1; con ...
- Windows10 上安装 Anaconda 后命令提示符(cmd)下无法执行(python / pip)命令解决方案
原文:https://blog.csdn.net/qq_38644840/article/details/85064408 安装Anaconda后一段时间内能够在命令提示符(cmd)界面运行pytho ...
- python多任务的实现:线程,进程,协程
什么叫“多任务”呢?简单地说,就是操作系统可以同时运行多个任务.打个比方,你一边在用浏览器上网,一边在听MP3,一边在用Word赶作业,这就是多任务,至少同时有3个任务正在运行.还有很多任务悄悄地在后 ...
- linux技能四 用户管理
用户管理:用户类型,添加用户,修改用户,删除用户,查看用户信息,用户的切换,添加组,修改组,删除组,查看组 用户类型:超级用户:root,UID=1 系统用户:运行系统服务的,不能登陆的,UID=(1 ...
- C++类中创建线程
经常会遇到需要在类中创建线程,可以使用静态成员函数,并且将类实例的指针传入线程函数的方式来实现. 实现代码代码如下: /* 类头文件 CTestThread.h */ #include<io ...
- 为安卓项目添加FileProvider
简单记录 android7.0开始出现FileProvider.从一个小白角度看需要注意这几点: Manifest.xml中添加provider节点 添加xml文件 模块的build.gradle中添 ...
- Linux DNS 主从复制
设置主从DNS的主要是为了冗余,分担压力,防止服务器宕机后,DNS无法正常解析. 配置 master 正常配置DNS服务. 设置主机名 [root@localhost ~]# hostnamectl ...
- linux虚拟串口及远程访问
1. 虚拟终端概念 linux中有很多终端,如下简单介绍下各种终端或串口的概念. 1.1 tty:终端设备的统称 tty是Teletype或TeletypeWriter的缩写,中文翻译为电传打字机.电 ...