这种鲜明的玄学风格很明显就是十几年前的题目。

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)的更多相关文章

  1. bzoj 1085骑士精神

    bzoj 1085骑士精神 在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士,且有一个空位.在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2 ...

  2. A*算法详解 BZOJ 1085骑士精神

    转载1:A*算法入门 http://www.cppblog.com/mythit/archive/2009/04/19/80492.aspx 在看下面这篇文章之前,先介绍几个理论知识,有助于理解A*算 ...

  3. bzoj 1085骑士精神 迭代深搜

    题目传送门 题目大意:给出一幅棋盘,问能否复原,中文题面,不做解释. 思路:第一次写迭代深搜的题目,这道题还是挺经典的.这道题的状态很明显的每多搜一层就是多八倍,非常的多,而且又是t组输入,所以必定有 ...

  4. BZOJ 1085 骑士精神 迭代加深搜索+A*

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1085 题目大意: 在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个 ...

  5. [bzoj] 1085 骑士精神 || ID-DFS

    原题 找到最少的步数成为目标状态. IDDFS(限制层数的dfs)即可 #include<cstdio> #include<algorithm> using namespace ...

  6. BZOJ 1085 / LOJ 2151 [SCOI2005]骑士精神 (剪枝/A*迭代搜索)

    题目大意:略 直接爆搜会T,我们优化一下,统计出当前棋盘和目标棋盘不同的位置的数量k,那么当前棋盘变成目标棋盘最少的移动次数是k-1 每次选择一个最大深度ma,那么如果当前走了dep步,显然必须保证d ...

  7. 『骑士精神 IDA*』

    骑士精神(SCOI2005) Description 在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位.在任何时候一个骑士都能按照骑 士的走法(它可以走到和它横坐标相差为1,纵 ...

  8. Bzoj 1085: [SCOI2005]骑士精神 (dfs)

    Bzoj 1085: [SCOI2005]骑士精神 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1085 dfs + 剪枝. 剪枝方法: ...

  9. BZOJ 1085: [SCOI2005]骑士精神( IDDFS + A* )

    一开始写了个 BFS 然后就 T 了... 这道题是迭代加深搜索 + A* -------------------------------------------------------------- ...

随机推荐

  1. 【iOS】swift 排序Sort函数用法(包含NSDictionary排序)

    用了几分钟做的简单翻译 一个例子 直接贴代码,不过多解释 //这是我们的model class imageFile { var fileName = String() var fileID = Int ...

  2. Hibernate之深入Hibernate的映射文件

    这周周末 要把hibernate的映射文件搞定 .. 1.映射文件的主结构 主要结构  :根元素为<hibernate-mapping ></hibernate-mapping> ...

  3. 《高级软件测试》11.15.全组完成jira安装,开始任务的部分书写

    今日任务完成情况如下: 小段:完成linux环境上jira的安装,并将jira的安装过程录制下来 小费:完成linux环境下jira的安装,开始部分任务的书写 小高:完成了jira的安装,并进一步熟悉 ...

  4. Syabse数据库无法启动的解决方案

    在探讨本问题之前,首先要为大家解释一下Syabse数据库本身.Syabse数据库应用和本身的架构相对而言都相对比较复杂,多数技术人员及公司对Sybase数据库底层结构和运行机制也处于并非完全了解的阶段 ...

  5. python之路--day13-模块

    1,什么是模块 模块就是系统功能的集合体,在python中,一个py文件就是一个模块, 例如:module.py 其中module叫做模块名 2,使用模块 2.1 import导入模块 首次带入模块发 ...

  6. python 中 reduce 函数的使用

    reduce()函数也是Python内置的一个高阶函数. reduce()函数接收的参数和 map()类似,一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接 ...

  7. JavaScript利用数组原型,添加方法实现遍历多维数组每一个元素

    原型就是提供给我们为了让我们扩展更多功能的. 今天学习了用js模拟底层代码,实现数组多维的遍历.思想是在数组原型上添加一个方法. // js中的数组forEach方法,传入回掉函数 能够帮助我们遍历数 ...

  8. python/进程线程的总结

    python/进程线程的总结 一.进程和线程的描述: 进程:最小的资源管理单位 线程:最小的执行单位 执行一个进程时就默认执行一个线程(主线程) 进程和线程的工作方式: 串行: 假如共有A.B.C任务 ...

  9. Linux:crontab组件部署linux定时任务

    crontab简介 crond 是linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程,与windows下的计划任务类似,当安装完成操作系统后,默认会安装此服务 工具,并且会自动启动c ...

  10. POJ-2184 Cow Exhibition---01背包变形(负数偏移)

    题目链接: https://vjudge.net/problem/POJ-2184 题目大意: 给出num(num<=100)头奶牛的S和F值(-1000<=S,F<=1000),要 ...