HDU1242 Rescue

                                                             Rescue

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 11627    Accepted Submission(s): 4233


Problem Description
Angel was caught by the MOLIGPY! He was put in prison by Moligpy. The prison is described as a N * M (N, M <= 200) matrix. There are WALLs, ROADs, and GUARDs in the prison.

Angel's friends want to save Angel. Their task is: approach Angel. We assume that "approach Angel" is to get to the position where Angel stays. When there's a guard in the grid, we must kill him (or her?) to move into the grid. We assume that we moving up, down, right, left takes us 1 unit time, and killing a guard takes 1 unit time, too. And we are strong enough to kill all the guards.

You have to calculate the minimal time to approach Angel. (We can move only UP, DOWN, LEFT and RIGHT, to the neighbor grid within bound, of course.)
 

Input
First line contains two integers stand for N and M.

Then N lines follows, every line has M characters. "." stands for road, "a" stands for Angel, and "r" stands for each of Angel's friend.

Process to the end of the file.
 

Output
For each test case, your program should output a single integer, standing for the minimal time needed. If such a number does no exist, you should output a line containing "Poor ANGEL has to stay in the prison all his life."
 

Sample Input
   
   
   
   
7 8 #.#####. #.a#..r. #..#x... ..#..#.# #...##.. .#...... ........
 

Sample Output
   
   
   
   
13
 

Author
CHEN, Xue
 

Source
ZOJ Monthly, October 2003
 

Recommend
Eddy

解题思路:本题为广度优先搜索加强版,基本广搜+打怪,只要算上打怪的时间就可以了

       后话:本题纯属运气好,只是题目的测试数据比较单纯(简直弱爆了,我的flag[20][20](错误一,手误)这么小的数组也能过),让我的单纯的广搜也过了。其实题目的意思是,有多个朋友在找ANGEL,有一个人找到即可得救,我看成了只有一个朋友(错误二,题意)。对于这点,正解应该是从ANGEL的位置出发开始广搜,一旦搜到他的朋友,搜索成功。这种搜索方法的话,ANGEL可能中途要打怪,打怪要耗时,所以单纯的广搜,理论上也是错得(要是数据很强大的话也会挂掉)。所以,应该再加上优先队列,处理时间的先后,对打怪的耗时节点进行滞后处理。既使题目的意思是只有一个朋友在找ANGEL,我的原AC代码的思维也是错的(错误三,逻辑),竟然中途要打怪,所有节点就不一定是平行节点,所以,要使用优先队列进行打怪节点滞后处理。正解见:逆向bfs+优先队列AC代码(完)



单纯bfsAC代码
#include<cstdio> #include<cstring> #include<queue> using namespace std; int n,m; char map[200][200]; int flag[20][20]; int sx,sy,ex,ey; int dir[4][2]={1,0,0,1,-1,0,0,-1}; struct node {     int x;     int y;     int time; }; bool inmap(int x,int y) {     if(x>=0&&x<n&&y>=0&&y<m)         return true;     return false; } int bfs() {     node s,e;     queue<node> q;     s.x=sx;     s.y=sy;     s.time=0;     q.push(s);     while(!q.empty())     {         s=q.front();         q.pop();         for(int i=0;i<4;i++)         {             e.x=s.x+dir[i][0];             e.y=s.y+dir[i][1];             e.time=s.time+1;             if(inmap(e.x,e.y)&&!flag[e.x][e.y])             {                 if(e.x==ex&&e.y==ey)     //走到终点                 {                     return e.time;                 }                 if(map[e.x][e.y]=='x')     //打怪耗时                 {                     e.time++;                     map[e.x][e.y]='.';                 }                 if(map[e.x][e.y]=='.')                     q.push(e),flag[e.x][e.y]=1;             }         }     }     return -1; } int main() {     int i,j;     while(scanf("%d%d",&n,&m)!=EOF)     {         memset(flag,0,sizeof(flag));         for(i=0;i<n;i++)         {             scanf("%s",map[i]);             for(j=0;j<m;j++)             {                 if(map[i][j]=='a')                     sx=i,sy=j,map[i][j]='.';                 else if(map[i][j]=='r')                     ex=i,ey=j,map[i][j]='.';             }         }         int p=bfs();         if(p==-1)             printf("Poor ANGEL has to stay in the prison all his life.\n");         else             printf("%d\n",p);     }     return 0; } 


逆向bfs+优先队列AC代码

解题思路:1)先找到Angel所在点,标记为起点,记录坐标用于广搜;
                  2)以Angel所在点为起点开始广搜(广搜不是很好描叙,比较复杂,亲们还是看代码吧);
                  3)若中途遇到怪,则打怪,时间增加1;
                  4)一旦搜到
Angel任意一个朋友所在点,搜索成功,返回所用时间;
                  5)若所有能走得节点都访问过了,没有搜到
Angel的朋友,则搜索失败,返回-1;
                  6)搜索完成,若bfs返回的值为-1,说明搜索失败,输出“Poor ANGEL has to stay in the prison all his life.”,否则,输出bfs返回值即可。


#include<cstdio> #include<cstring> #include<queue> using namespace std; int n,m; char map[200][200]; int flag[200][200]; int sx,sy; int dir[4][2]={1,0,0,1,-1,0,0,-1}; struct node {     int x;     int y;     int time;     friend bool operator < (node a,node b)     {         return a.time>b.time;     }//用于优先队列,按队列中节点的时间属性先后排序 }; bool inmap(int x,int y) {     if(x>=0&&x<n&&y>=0&&y<m)         return true;     return false; } int bfs() {     node s,e;     priority_queue<node> q;     s.x=sx;     s.y=sy;     s.time=0;     flag[sx][sy]=1;     q.push(s);    //起点入队     while(!q.empty())     {         s=q.top();   //队列中用时最少的节点出队         q.pop();         for(int i=0;i<4;i++)    //四个方向搜索         {             e.x=s.x+dir[i][0];             e.y=s.y+dir[i][1];             e.time=s.time+1;             if(inmap(e.x,e.y)&&!flag[e.x][e.y])    //不越界,没有走过(可以处理)             {                 if(map[e.x][e.y]=='r')   //找到朋友(搜索成功)                 {                     return e.time;                 }                 if(map[e.x][e.y]=='x')   //打怪                 {                     e.time++;                     map[e.x][e.y]='.';                 }                 if(map[e.x][e.y]=='.')    //打怪后的节点或路的节点,入队                     q.push(e),flag[e.x][e.y]=e.time;             }         }     }     return -1;    //搜索完成,未搜到朋友(终点) } int main() {     int i,j;     while(scanf("%d%d",&n,&m)!=EOF)     {         memset(flag,0,sizeof(flag));     //记得初始化啊         for(i=0;i<n;i++)         {             scanf("%s",map[i]);             for(j=0;j<m;j++)                 if(map[i][j]=='a')     //记录起点                     sx=i,sy=j;         }         int p=bfs();    //开始广搜         if(p==-1)     //搜不到终点             printf("Poor ANGEL has to stay in the prison all his life.\n");         else             printf("%d\n",p);    //搜到终点     }     return 0; }


你可能感兴趣的:(C++,优先队列,广度优先搜索,bfs,打怪耗时)