hiho一下 第九十九周 #1308 : 搜索二·骑士问题 【宽度优先搜索】
来源:互联网 发布:网游网络加速器 编辑:程序博客网 时间:2024/05/17 23:07
#1308 : 搜索二·骑士问题
- 样例输入
2A1 A1 A1B2 D3 F4
- 样例输出
02
描述
小Hi:小Ho你会下国际象棋么?
小Ho:应该算会吧,我知道每个棋子的移动方式,马走日象飞田什么的...
小Hi:象飞田那是中国象棋啦!
小Ho:哦,对。国际象棋好像是走斜线来着。
小Hi:不过马走日倒是对了。国际象棋中的马一般叫做骑士,关于它有个很有意思的问题。
小Ho:什么啊?
小Hi:骑士巡游问题,简单来说就是关于在棋盘上放置若干个骑士,然后探究移动这些骑士是否能满足一定的而要求。举个例子啊:一个骑士从起始点开始,能否经过棋盘上所有的格子再回到起点。
小Ho:哦,看上去好像很难的样子。
小Hi:其实也还好了。简单一点的比如棋盘上有3个骑士,能否通过若干次移动走到一起。
小Ho:能够么?
小Hi:当然能够了。由于骑士特殊的移动方式,放置在任何一个初始位置的骑士,都可以通过若干次移动到达棋盘上任意一个位置。
小Ho:那么只要选定一个位置,把它们全部移动过去就好了是吧?
小Hi:是的,那么这里又有另一个问题了:要选择哪一个位置汇合,使得3个骑士行动的总次数最少?
小Ho:嗯,这个好像不是很难,让我想一想。
提示:骑士问题
输入
第1行:1个正整数t,表示数据组数,2≤t≤10。
第2..t+1行:用空格隔开的3个坐标, 每个坐标由2个字符AB组成,A为'A'~'H'的大写字母,B为'1'~'8'的数字,表示3个棋子的初始位置。
输出
第1..t行:每行1个数字,第i行表示第i组数据中3个棋子移动到同一格的最小行动步数。
提示:骑士问题
小Ho:小Hi你刚刚说到了这样一点:放置在任何一个初始位置的骑士,都可以通过若干次移动到达棋盘上任意一个位置。
那么我就可以把整个局面分开来做:我先计算出每一个骑士到达棋盘上每个位置的最短距离;再枚举每一个位置,表示将三个骑士在这个位置上汇合,累加这三个骑士到达的步数之和;最后选择一个最小的和作为解。
求解骑士到达每一个位置最少步数时,我可以使用之前讲过的宽度优先搜索。从而保证我第一次枚举到这个位置时就是最少的步数。
那么整个流程就是:
bfs_solve(f, x, y):f[][] = -1// 初始化为-1f[x][y] = 0// 起始点queue.push( (x,y) ) // 将初始点加入队列中while (!queue.isEmpty())(now_x, now_y) = queue.pop()// 弹出队列头元素For i = 1 .. 8// 枚举8种可能的移动(next_x, next_y) = move(now_x, now_y, i)If ((next_x, next_y) in chessboard AND f[next_x][next_y] equal -1)f[next_x][next_y] = f[now_x][now_y] + 1queue.push( (next_x, next_y) )End IfEnd ForEnd WhileFor i = 1 .. 3// 通过bfs求解// step[i][x][y]表示第i个骑士移动到(x,y)的最少步数bfs_solve(step[i][][], initialX[i], initialY[i])End ans = InfiniteFor x = A .. HFor y = 1 .. 8If (ans > sigma(step[][x][y])) Thenans = sigma(step[][x][y])End IfEnd ForEnd For
小Hi:小Ho挺厉害的嘛,这样的确把问题解决了。不过我这里还有另一种方法,虽然同样是通过宽度优先搜索来搜索最少步数,但是我将三个骑士的位置看做了一个整体。
由于每一个骑士的位置都是由2个坐标来决定,这俩个坐标恰好可以对应一个2位的八进制数。若我把3个坐标合起来,就可以用一个6位的八进制数来表示。比如"B2 D3 F4",就表示为"113253"。
由此可以通过一个大小为8^6的布尔数组来进行状态的判重。而每一次的状态转移也从原来的仅枚举8个方向,变成了枚举骑士加枚举方向,一共有3*8=24种可能。
此方法的伪代码为:
queue.push( initialStatus ) // 将初始的8进制数加入队列中while (!queue.isEmpty())now_status = queue.pop()// 弹出队列头元素For i = 1 .. 3// 枚举移动的其实For j = 1 .. 8// 枚举8种可能的移动next_status = move(now_status, i, j)// 移动骑士并记录状态If (next_status is valid AND not visited[ next_status ])step[ next_status ] = step[ now_status ] + 1queue.push( next_status )If (check(next_status)) Then// 检查这个八进制数是否满足3个坐标重合Return step[ next_status ]End If End IfEnd ForEnd While
在进行检查是否已经走到一起时,可以通过一个位运算来做:
check(status):Return ((status and 0x3f) == ((status rsh 6) and 0x3f)) and (((status rsh 6) and 0x3f) == ((status rsh 12) and 0x3f))// rsh表示右移操作
小Ho:哦,这样就可以不用计算出每个骑士走到每个点的步数,而是在过程中就有可能直接求解到最先汇合位置的步数。
小Hi:对,不过这个算法中状态的转移会稍微复杂一点。你可以选择一个你比较喜欢的方法来实现。
小Ho:好!
代码:
#include<cstdio>#include<queue>#include<cstring>#include<algorithm>using namespace std;struct node{ int x,y,step; bool friend operator <(node xx,node yy) { return xx.step>yy.step; }}now,qian;int ma[10][10][3],dis[10][10];bool fafe[10][10];void dfs(int x,int y){ memset(fafe,false,sizeof(fafe)); priority_queue<node > que; now.step=0; now.x=x; now.y=y; fafe[x][y]=true; que.push(now); while (!que.empty()) { now=que.top(); que.pop(); x=now.x; y=now.y; dis[x][y]=now.step; if (x+1<=8) { if (y+2<=8) if (!fafe[x+1][y+2]) { fafe[x+1][y+2]=true; qian.x=x+1; qian.y=y+2; qian.step=now.step+1; que.push(qian); } if (y-2>0) if (!fafe[x+1][y-2]) { fafe[x+1][y-2]=true; qian.x=x+1; qian.y=y-2; qian.step=now.step+1; que.push(qian); } if (x+2<=8) { if (y+1<=8) if (!fafe[x+2][y+1]) { fafe[x+2][y+1]=true; qian.x=x+2; qian.y=y+1; qian.step=now.step+1; que.push(qian); } if (y-1>0) if (!fafe[x+2][y-1]) { fafe[x+2][y-1]=true; qian.x=x+2; qian.y=y-1; qian.step=now.step+1; que.push(qian); } } } if (x-1>0) { if (y+2<=8) if (!fafe[x-1][y+2]) { fafe[x-1][y+2]=true; qian.x=x-1; qian.y=y+2; qian.step=now.step+1; que.push(qian); } if (y-2>0) if (!fafe[x-1][y-2]) { fafe[x-1][y-2]=true; qian.x=x-1; qian.y=y-2; qian.step=now.step+1; que.push(qian); } if (x-2>0) { if (y+1<=8) if (!fafe[x-2][y+1]) { fafe[x-2][y+1]=true; qian.x=x-2; qian.y=y+1; qian.step=now.step+1; que.push(qian); } if (y-1>0) if (!fafe[x-2][y-1]) { fafe[x-2][y-1]=true; qian.x=x-2; qian.y=y-1; qian.step=now.step+1; que.push(qian); } } } }}void slove(int a,int b,int c,int d,int e,int f){ // printf("%d %d %d %d %d %d\n",a,b,c,d,e,f); dfs(a,b); for (int i=1;i<9;i++) for (int j=1;j<9;j++) ma[i][j][0]=dis[i][j]; dfs(c,d); for (int i=1;i<9;i++) for (int j=1;j<9;j++) ma[i][j][1]=dis[i][j]; dfs(e,f); for (int i=1;i<9;i++) for (int j=1;j<9;j++) ma[i][j][2]=dis[i][j]; int ans=999; for (int i=1;i<9;i++) for (int j=1;j<9;j++) ans=min(ans,ma[i][j][0]+ma[i][j][1]+ma[i][j][2]); printf("%d\n",ans);}int main(){ int t;scanf("%d",&t); char ch[5][5]; while (t--) { scanf("%s%s%s",ch[0],ch[1],ch[2]); slove(ch[0][0]-'A'+1,ch[0][1]-'0',ch[1][0]-'A'+1,ch[1][1]-'0',ch[2][0]-'A'+1,ch[2][1]-'0'); } return 0;}
- hiho一下 第九十九周 #1308 : 搜索二·骑士问题 【宽度优先搜索】
- HIHO #1308 : 搜索二·骑士问题
- hiho一下 第九十九周
- 搜索二·骑士问题
- hiho一下 第九十八周题目1 : 搜索一·24点
- hiho一下 第九十八周 题目1 : 搜索一·24点
- hihoCoder搜索二·骑士问题
- hiho一下 第九十八周 #1304 : 搜索一·24点 【此方法好巧妙呀---用来求24点】
- 宽度优先搜索练习(二)
- hihoCoder搜索二---骑士问题---暴力法
- 深度优先搜索 骑士周游列国
- hiho一下 第四十九周
- hiho一下 第五十九周
- 宽度优先搜索 BFS
- 宽度优先搜索BFS
- 宽度优先搜索
- 宽度优先搜索图
- 宽度优先搜索
- 优秀程序员的七大特征,你具备几条?
- C语言学习入门 (六) 预处理指令:宏、条件编译、文件包含
- 【软考总结】——IOS/OS体系结构
- 【11.6十一月第一周总结】
- UVA 难度分级 (转)
- hiho一下 第九十九周 #1308 : 搜索二·骑士问题 【宽度优先搜索】
- C语言二维数组的定义和引用
- html css javascript自学习入门级测验试题
- 凸优化
- VR学习第十二节:VR目前发展的状况到底是怎样的?(2016)
- centos github pycharm--错误提示
- oracle日志文件学习
- linux 常用指令大全
- Thinkphp ajax传值与显示