[BZOJ]1085 骑士精神(SCOI2005)
这种鲜明的玄学风格很明显就是十几年前的题目。
Description
在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空位上。 给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步数完成任务。

Input
第一行有一个正整数T,表示一共有N组数据。接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑士,*表示空位。两组数据之间没有空行。
Output
对于每组数据都输出一行。如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出-1。
Sample Input
2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100
Sample Output
7
-1
HINT
T<=10。
Solution
拿到这道题应该没有别的想法吧,于是我们直接开始往搜索去想。
由于步数最多只有15,所以最暴力的暴力的时间复杂度为O(T*25*815)。
如果用A*算法解决这道题,估价函数为不符合答案的格子个数,如果剩余步数小于这个值,那么这个状态一定不能在15步内走到答案。
复杂度似乎可以不用乘上25,所以理论时间复杂度上限为O(T*815)。
所以A*算法就是这么神奇地通过该题的,网络上题解有很多,小C就不再赘述。
都是玄学。
所以小C还是介绍一下自己的折半搜索做法吧。
从目标状态往前搜8步,用一个map把每个状态hash的答案存下来。
从每个起始状态往后搜7步,对于每个状态到map查找并更新答案。
理论时间复杂度O(25*88*log(state)+T*25*87*log(state))。
加一个判重的剪枝,可以跑得飞快。
map还可以用O(1)的,hash还可以动态维护。所以时间复杂度可以优化到O(88+T*87)。
而且每个状态不是满的8种转移方式,实际的时间复杂度远远小于上限。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#define ll unsigned long long
using namespace std;
typedef char matr[][];
const int fx[][]={{,},{,-},{-,},{-,-},{,},{,-},{-,},{-,-}};
map <ll,int> mp;
matr c,d;
int cx,cy,dx,dy,ans,t; inline int read()
{
int n=,f=; char c=getchar();
while (c<'' || c>'') {if(c=='-')f=-; c=getchar();}
while (c>='' && c<='') {n=n*+c-''; c=getchar();}
return n*f;
} ll geth(matr c,int x,int y)
{
ll h=;
register int i,j;
for (i=;i<=;++i)
for (j=;j<=;++j) h=h*+c[i][j]-'';
h=h*+x-; h=h*+y-;
return h;
} bool check(int x,int y) {return x<||x>||y<||y>;} void dfs1(int stp)
{
ll h=geth(c,cx,cy);
if (mp[h]&&mp[h]<=stp) return;
mp[h]=stp;
if (stp>) return;
register int i,ncx,ncy;
for (i=;i<;++i)
{
ncx=cx+fx[i][];
ncy=cy+fx[i][];
if (check(ncx,ncy)) continue;
swap(c[cx][cy],c[ncx][ncy]);
swap(cx,ncx); swap(cy,ncy);
dfs1(stp+);
swap(cx,ncx); swap(cy,ncy);
swap(c[cx][cy],c[ncx][ncy]);
}
} void dfs2(int stp)
{
ll h=geth(d,dx,dy);
if (mp[h]) ans=min(ans,stp+mp[h]-);
if (stp>) return;
register int i,ndx,ndy;
for (i=;i<;++i)
{
ndx=dx+fx[i][];
ndy=dy+fx[i][];
if (check(ndx,ndy)) continue;
swap(d[dx][dy],d[ndx][ndy]);
swap(dx,ndx); swap(dy,ndy);
dfs2(stp+);
swap(dx,ndx); swap(dy,ndy);
swap(d[dx][dy],d[ndx][ndy]);
}
} int main()
{
register int i,j;
t=read();
for (i=;i<=;++i)
for (j=;j<=;++j)
if (i<j||i==j&&i<=) c[i][j]='';
else if (i>j||i==j&&i>=) c[i][j]='';
cx=cy=; dfs1();
while (t--)
{
ans=;
for (i=;i<=;++i) scanf("%s",d[i]+);
for (i=;i<=;++i)
{
for (j=;j<=;++j)
if (d[i][j]=='*') {dx=i; dy=j; d[i][j]=''; break;}
if (j<=) break;
}
dfs2();
printf("%d\n",ans==?-:ans);
}
}
Last Word
不过仔细想想玄学题目并不只是十几年前的专利啊,比如FJOI的D2T2……
[BZOJ]1085 骑士精神(SCOI2005)的更多相关文章
- bzoj 1085骑士精神
bzoj 1085骑士精神 在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士,且有一个空位.在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2 ...
- A*算法详解 BZOJ 1085骑士精神
转载1:A*算法入门 http://www.cppblog.com/mythit/archive/2009/04/19/80492.aspx 在看下面这篇文章之前,先介绍几个理论知识,有助于理解A*算 ...
- bzoj 1085骑士精神 迭代深搜
题目传送门 题目大意:给出一幅棋盘,问能否复原,中文题面,不做解释. 思路:第一次写迭代深搜的题目,这道题还是挺经典的.这道题的状态很明显的每多搜一层就是多八倍,非常的多,而且又是t组输入,所以必定有 ...
- BZOJ 1085 骑士精神 迭代加深搜索+A*
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1085 题目大意: 在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个 ...
- [bzoj] 1085 骑士精神 || ID-DFS
原题 找到最少的步数成为目标状态. IDDFS(限制层数的dfs)即可 #include<cstdio> #include<algorithm> using namespace ...
- BZOJ 1085 / LOJ 2151 [SCOI2005]骑士精神 (剪枝/A*迭代搜索)
题目大意:略 直接爆搜会T,我们优化一下,统计出当前棋盘和目标棋盘不同的位置的数量k,那么当前棋盘变成目标棋盘最少的移动次数是k-1 每次选择一个最大深度ma,那么如果当前走了dep步,显然必须保证d ...
- 『骑士精神 IDA*』
骑士精神(SCOI2005) Description 在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位.在任何时候一个骑士都能按照骑 士的走法(它可以走到和它横坐标相差为1,纵 ...
- Bzoj 1085: [SCOI2005]骑士精神 (dfs)
Bzoj 1085: [SCOI2005]骑士精神 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1085 dfs + 剪枝. 剪枝方法: ...
- BZOJ 1085: [SCOI2005]骑士精神( IDDFS + A* )
一开始写了个 BFS 然后就 T 了... 这道题是迭代加深搜索 + A* -------------------------------------------------------------- ...
随机推荐
- segmentedControl设置字体和字体颜色问题
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:[UIColor blackColor],UITextAttributeT ...
- Flask 学习 六 大型程序结构
pip freeze >requirement.txt 自动生成版本号 pip install -r requirement.txt 自动下载对应的库 梳理结构 config.py #!/usr ...
- Vim 中文社区:期待你的加入
我们的愿景 Vim 中文社区一直比较零散,缺少凝聚力,现有的一些群经常也是水的可以的,讨论各种无关紧要的内容,于是导致很大一部分人,将这些群丢入了群助手,渐渐地他们也淡出了 vim 中文社区. 而我理 ...
- Aache的虚拟主机配置虚拟目录
3. 打开 httpd.conf 文件, 添加如下代码: # Virtual hosts Include conf/extra/httpd-vhosts.conf 如果已存在,将Include前面的# ...
- java排序算法之冒泡排序(Bubble Sort)
java排序算法之冒泡排序(Bubble Sort) 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一趟:首先比较第1个和第2个数 ...
- 爬虫系列(1)-----python爬取猫眼电影top100榜
对于Python初学者来说,爬虫技能是应该是最好入门,也是最能够有让自己有成就感的,今天在整理代码时,整理了一下之前自己学习爬虫的一些代码,今天先上一个简单的例子,手把手教你入门Python爬虫,爬取 ...
- 获取apk项目的MD5值和SHA1值
一些可说可不说的话: * 以前有一个更简单的方法,在as的右边工具栏的 gradle 面板中可以很方便的获取到: * 上次用也是在2年前,时间长了给忘记了,不过我记得我当时写了笔记,这会笔记不在身边, ...
- linux下xargs和管道的区别
管道将前面的标准输出作为后面的标准输入,xargs则将标准输入作为命令的参数 一.简介 1.背景 之所以能用到这个命令,关键是由于很多命令不支持|管道来传递参数,而日常工作中有有这个必要,所以就有了x ...
- ELK学习总结(3-3)elk的组合查询
1.bool 查询: must: 必须 should: 可以满足,也可以不满足. must_not: minimum_should_match: 至少要x个匹配才算匹配成功 disable_coor ...
- Android开发——发布第三方库到JitPack上
前言: 看到大神们的写的第三方控件,比较好用,我们使用的时候直接是在gradle上加上代码就可以使用了,现在到我们写了一个第三方控件,想要别人使用的时候也是直接在gradle加上相关的代码就可以用了, ...