博客参考http://blog.csdn.net/u011932355/article/details/44344725
3 5 6 XXXXXX XZ..ZX XXXXXX M.G... ...... 5 6 XXXXXX XZZ..X XXXXXX M..... ..G... 10 10 .......... ..X....... ..M.X...X. X......... .X..X.X.X. .........X ..XX....X. X....G...X ...ZX.X... ...Z..X..X
1 1 -1
题目大意:
一张n*m大的地图上有五种东西分别:
‘. ’:路
‘X':墙
’Z':鬼魂:每一个单位时间开始的时候会衍生出新的鬼 每个单位时间开始的时候都衍生出两个单位长度.(一圈)
‘M’:主人公.腿脚比较麻溜 每一个单位时间内可以行动3次(移动三个格子).
‘G’:主人公的女朋友 每一个单位时间内可以行动一次(移动1个格子).
问两人是否可以成功碰面,再不被鬼吃掉的前提下
思路:
双向广搜 .应用曼哈顿距离判断是否在鬼魂的范围内.
这里先贴上初始化的变量部分:
#include <stdio.h> #include <string.h> #include <algorithm> #include <queue> using namespace std; const int dir[4][2]={ {1,0},{-1,0},{0,1},{0,-1} };//走法 char str[810][810];//地图 int used[2][810][810];//标记是否走过 int g_x,g_y,m_x,m_y,n,m,step;//主人公女朋友的坐标, 主人公的坐标,step是回合(多少单位时间).<span style="font-family: Arial;"> </span>并且初始化init
void init() { int i,j,cnt; scanf("%d%d",&n,&m); for (i=0;i<n;i++) scanf("%s",str[i]);//读图 cnt=0; for (i=0;i<n;i++) for (j=0;j<m;j++)//初始化各种标记 { if (str[i][j]=='G') { g_x=i; g_y=j; } if (str[i][j]=='M') { m_x=i; m_y=j; } if (str[i][j]=='Z') { z[cnt].x=i; z[cnt].y=j; cnt++; } } }
用于标记主人公和他女朋友走过的位子.
简单bfs可知用一个队列就能完成 这里当然要用两个队列来完成.一个队列用于存主人公走到的位子 一个队列用于存女朋友走到的位子..
既然是双向bfs有两个物体在行动 即使是同时行动,我们用代码实现也是很难的 所以我们先看成一个先动 另一个后动.这样就能完成双向bfs的实现
至于如何实现走3步 这里读者可以先想一想 并对应下列代码思考:
sum=q[w].size(); while (sum--)
这里贴上代码和详解:
int bfs(int w)//w如果是0表示是主人公 如果是1表示是女朋友.//这里我要准备走多次.//下边一组代码贴上如何实现走多次 { node cur,next; int i,sum; sum=q[w].size();//因为我要准备走多次 而不是一次一个人 走完全部能走的路.请体会一下. while (sum--) { cur=q[w].front(); q[w].pop(); if (judge(cur)==0) continue;//上一轮这个点没有被鬼魂覆盖 不代表这一轮就没有被鬼魂覆盖~ for (i=0;i<4;i++) { next.x=cur.x+dir[i][0]; next.y=cur.y+dir[i][1]; if (judge(next)==0) continue; if (used[w][next.x][next.y]==0) { if (used[1-w][next.x][next.y]==1) return 1;//如果女朋友能走到的地方 主人公能走的到(在合法的情况下(各种判断一定合法了)就代表两个人能相遇) used[w][next.x][next.y]=1; q[w].push(next); } } } return 0; }
while ((!q[0].empty()) || (!q[1].empty()))//如果有一方没有能走的方式了 就代表game over了 { step++;//回合++ if (bfs(0)==1) return step; if (bfs(0)==1) return step; if (bfs(0)==1) return step;//男主走3次 if (bfs(1)==1) return step;//女朋友走1次. }//如此一来就能实现男主走三次之后女朋友走一次了(两者不能同时动 就先定一个 走另一个 (而且想用队列控制男主走3次不太现实 这样实现还是比较容易理解的).)所以就有了以上的int sum=s[w].size();的操作了,每一次男主行走都把上一步能走到的点都继续向下走了 而且没有涉及到这次走完的步向下走
//这里只可意会 不可言传 也许我这里语言描叙并不是恰到好处 且行且珍惜.
那么如何判断现在我走到的地方没有被鬼魂所覆盖呢?
这里涉及到一个曼哈顿距离的问题~
这里贴上一个曼哈顿距离的算法讲解帖子(百度搜的)http://www.cnblogs.com/jiahuafu/p/4013873.html
int judge(node b) { if (b.x<0 || b.y<0 || b.x>=n || b.y>=m) return 0; if (str[b.x][b.y]=='X') return 0; if ((abs(b.x-z[0].x)+abs(b.y-z[0].y))<=2*step) return 0;//曼哈顿距离判断问题. if ((abs(b.x-z[1].x)+abs(b.y-z[1].y))<=2*step) return 0; return 1; }
#include <stdio.h> #include <string.h> #include <algorithm> #include <queue> using namespace std; const int dir[4][2]={ {1,0},{-1,0},{0,1},{0,-1} }; char str[810][810]; int used[2][810][810]; int g_x,g_y,m_x,m_y,n,m,step; struct node { int x,y; }ncur,z[2]; queue<node>q[2]; void init() { int i,j,cnt; scanf("%d%d",&n,&m); for (i=0;i<n;i++) scanf("%s",str[i]); cnt=0; for (i=0;i<n;i++) for (j=0;j<m;j++) { if (str[i][j]=='G') { g_x=i; g_y=j; } if (str[i][j]=='M') { m_x=i; m_y=j; } if (str[i][j]=='Z') { z[cnt].x=i; z[cnt].y=j; cnt++; } } } int judge(node b) { if (b.x<0 || b.y<0 || b.x>=n || b.y>=m) return 0; if (str[b.x][b.y]=='X') return 0; if ((abs(b.x-z[0].x)+abs(b.y-z[0].y))<=2*step) return 0;//曼哈顿距离判断问题. if ((abs(b.x-z[1].x)+abs(b.y-z[1].y))<=2*step) return 0; return 1; } int bfs(int w) { node cur,next; int i,sum; sum=q[w].size(); while (sum--) { cur=q[w].front(); q[w].pop(); if (judge(cur)==0) continue; for (i=0;i<4;i++) { next.x=cur.x+dir[i][0]; next.y=cur.y+dir[i][1]; if (judge(next)==0) continue; if (used[w][next.x][next.y]==0) { if (used[1-w][next.x][next.y]==1) return 1; used[w][next.x][next.y]=1; q[w].push(next); } } } return 0; } int solve() { while (!q[0].empty()) q[0].pop(); while (!q[1].empty()) q[1].pop(); ncur.x=m_x; ncur.y=m_y; q[0].push(ncur); ncur.x=g_x; ncur.y=g_y; q[1].push(ncur); memset(used,0,sizeof(used)); used[0][m_x][m_y]=used[1][g_x][g_y]=1; step=0; while ((!q[0].empty()) || (!q[1].empty())) { step++; if (bfs(0)==1) return step; if (bfs(0)==1) return step; if (bfs(0)==1) return step; if (bfs(1)==1) return step; } return -1; } int main() { int t; scanf("%d",&t); while (t--) { init(); printf("%d\n",solve()); } return 0; }