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算法求出来的边,其余的边都可以删掉,于是就有了这 ...
随机推荐
- java之spring mvc之页面跳转
1. 如果返回值为ModelAndView,在处理方法中,返回null时,默认跳转的视图名称为请求名.跳转结果会根据视图解析器来跳转. @RequestMapping("/hello.do& ...
- json.dumps()包装中文字符串
开发环境 系统: ubuntu18.04 系统编码: $LANG = en_US.UTF-8 python解释器版本: Python 3.6.7 乱码现场 使用 json.dumps() 将 dict ...
- python二维数组切片
python中list切片的使用非常简洁.但是list不支持二维数组.仔细研究了一下发现,因为list不是像nampy数组那么规范.list非常灵活.所以没办法进行切片操作. 后来想了两个办法来解决: ...
- 通过创建一个简单的骰子游戏来探究 Python
在我的这系列的第一篇文章 中, 我已经讲解如何使用 Python 创建一个简单的.基于文本的骰子游戏.这次,我将展示如何使用 Python 模块 Pygame 来创建一个图形化游戏.它将需要几篇文章才 ...
- Flask蓝图Blueprint和特殊装饰器
Flask 中的 蓝图 Blueprint 不能被run的flask实例:相当于django中的app01 应用 蓝图作用:功能隔离 路由隔离 Blueprint就是 一个不能run的flask 蓝图 ...
- 笔谈kxmovie开源播放器库的使用
开源播放器项目 kxmovie(https://github.com/kolyvan/kxmovie),现在仍然是很多刚开始接触播放器开发的程序员的参照范本.以下是我操作kxmovie项目的过程: ( ...
- Node: Process模块 (Features of Process)
Process模块 (Features of Process) process is a global variable which indicates the current Node.js pro ...
- Centos7搭建Harbor私有仓库(二)
1 说明 前文Centos7搭建Harbor私有仓库(一)中成功搭建了Harbor,但,是以http方式搭建的,这里我们修改为https方式 以下基于镜像CentOS-7-x86_64-Minimal ...
- PHP生成小程序二维码
/** * [生成小程序二维码] * @return [type] [description] */ public function makeMiniQrcode_do() { begin: $id ...
- NT Kernel & System (ntoskrnl)占用80端口
释放80端口 netstat -ano|findstr "80" 查询占用的进程 , PID =4 发现是system进程 无法直接kill. 1. 关闭iis的默认网站的80端口 ...