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算法求出来的边,其余的边都可以删掉,于是就有了这 ...
随机推荐
- Windows 创建 Redis 和 zookeeper 系统服务
Redis 启动 Redis start cmd /k "cd/d c:\Redis-x64-3.2.100\&&echo start Redis &&red ...
- 反射之关于MethodInfo的使用
1.MethodInfo类是在System.Reflection命名空间底下,既然是在Reflection空间底下.故名思议关于反射相关的操作,其中比较重要的方法是Invoke()方法,它是加载相同程 ...
- 自学Python编程的第八天----------来自苦逼的转行人
2019-09-18-21:11:24(初学者不会学博客,望大家见谅见谅) 今天学的内容是有关list..dict.set集合的使用方法和注意事项 list和dict在循环中不可删,而且list在迭代 ...
- SpringBoot启动原理详解
SpringBoot和Spring相比,有着不少优势,比如自动配置,jar直接运行等等.那么SpringBoot到底是怎么启动的呢? 下面是SpringBoot启动的入口: @SpringBootAp ...
- 全选全不选案例table表格
全选全不选案例table表格 案例一纯table表格 <table class="table table-bordered"> <thead class=&quo ...
- 设计的一些kubernetes面试题
公司现在上了一部分的业务至k8s,老实说,我心里很慌,在项目改造中,每天都会遇到很多问题,好友找我出一份k8s面试题,参考了网上的一些,再加上自己公司遇到的一些问题,整理如下: 参考链接:http:/ ...
- 使用PATH变量进行Linux权限升级技巧
0x00 前言 在解决了几个OSCP挑战之后,我们决定写一篇关于用于Linux权限升级的各种方法的文章,这对我们的读者在其渗透测试项目中有所帮助.在本文中,我们将学习“使用$path变量的各种方法”以 ...
- (摘录笔记)JAVA学习笔记SSH整合搭建项目
1:当然是导jar包啦: struts2: spring: hibernate: 至于这些jar包是什么作用,我想就不必我解释了,大家都懂得,ssh2基本的jar包: 还有一些其他jar包:strut ...
- js 获取 对象 属性名称(转载)
来源:https://www.cnblogs.com/YuyuanNo1/p/9257634.html dataObj = {name : su,age : 26,height : 18cm }; f ...
- Eureka 中服务下线的几种方式
原文:https://blog.csdn.net/qq_15071263/article/details/85276486#1_6 Eureka 中服务下线的几种方式1.直接停掉服务根据默认的策略,如 ...