[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* -------------------------------------------------------------- ...
随机推荐
- Linux 帳號管理與 ACL 權限設定
1. Linux 的账号与群组1.1 使用者识别: UID 与 GID1.2 使用者账号:/etc/passwd, /etc/shadow1.3 关于群组: 有效与初始群组. groups, newg ...
- 使用 PHP 来做 Vue.js 的 SSR 服务端渲染
对于客户端应用来说,服务端渲染是一个热门话题.然而不幸的是,这并不是一件容易的事,尤其是对于不用 Node.js 环境开发的人来说. 我发布了两个库让 PHP 从服务端渲染成为可能.spatie/se ...
- Xdebug的优点!php代码开发
可以跟踪函数,知道那个函数出错,之前只是输出一点调试信息,只是哪一行错了,并且是白色 如果是死循环,debug会对死循环判断一百次的循环,并且会给出每一次循环的时间,内存,和函数名,位置.根据时间可以 ...
- 如何将portfolio产品图片上的悬停去掉?
在Avada主题里,文章和portfolio的分类界面的图片,鼠标移入后都会出现这个东西 那么如何把它去掉,改为直接点击产品图片后进入产品详情页呢? 在theme option里搜索image rol ...
- window.open()参数详解及对浏览器的兼容性
因为篇幅,window.open()浏览器的兼容性请点击 这里 Part1:参数详解 window.open(url,name,param) url:即将打开的子窗口的地址:比如 "http ...
- ASP.NET MVC5 Forms登陆+权限控制(控制到Action)
一.Forms认证流程 请先参考如下网址: http://www.cnblogs.com/fish-li/archive/2012/04/15/2450571.html 本文主要介绍使用自定义的身份认 ...
- 发布到NPMJS
最近在做微服务的前后端设计,打算将客户端中的一个模块独立出来发布到npmjs上,因此,有机会了解了一下npm的发布过程. 参考了很多网上的文章,长篇累牍(但在这里还是真心感谢他们的分享),最终总结成一 ...
- C# JavaScriptSerializer找不到引用
遇到一个问题,还是第一次遇到,虽然比较简单,还是记录一下 一.写了一个小工具,为了方便就建了个Form窗体,结果用到了JavaScriptSerializer类,可是怎么都找不到System.Web. ...
- python—-模块与包1
模块与包 1 什么是模块? 一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀 2 为何要使用模块? 如果你对出python解释器然后重新进入,那么你之前定义的函数 ...
- scrapy爬取西刺网站ip
# scrapy爬取西刺网站ip # -*- coding: utf-8 -*- import scrapy from xici.items import XiciItem class Xicispi ...