杭电1242————搜索之优先队列

来源:互联网 发布:淘宝活动招商入口 编辑:程序博客网 时间:2024/04/24 02:12


Rescue

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


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


题目描述很简单,有些小陷阱。
1.题目没有说明是否只有一个救援队,假定有多个,则以天使为起点搜索最近的救援队是一种比较保险的做法
2.题目中说明了是最少的时间数而不是步数(步长)所以要注意对BFS进行改造

下面贴出代码
第一类:(直接从BFS的基础上更改的AC,杭电跑46MS........当然杭电的数据一般都比较的弱)
<span style="font-family:Microsoft YaHei;font-size:14px;">#include <cstdio>#include <cstring>#include <iostream>#define maxn 210using namespace std;struct queue{int x,y,time; /*time即是最后要求的时间数*/};int dx[4] = {1,-1,0,0},dy[4] = {0,0,1,-1};char maze[maxn][maxn];int  vis[maxn][maxn];char str[maxn];struct queue q[1000];/*辅助队列*/ int n,m,angle_x,angle_y;/*题目要求的是时间最少而不是步数最少,优先队列很适合解决这样的问题*/ void read(){      </span>
<span style="font-family:Microsoft YaHei;font-size:14px;">       /*注意在读入一大串字符的时候,为了保险起见使用cin比较好一些,用scanf还需要填一些个getchar()之类的小语句*/</span>
<span style="font-family:Microsoft YaHei;font-size:14px;">       /*数据量过大时用cin会超时,原理暂时不清楚,所以用什么方式还是根据题目的数据量和个人习惯memset(maze,'0',sizeof(maze));/*初始化迷宫为0,即无法通过的*/ memset(vis,0,sizeof(vis));/*全部未访问过*/ for(int i = 0;i < n;i++){for(int j = 0;j < m;j++){cin>>maze[i][j];if(maze[i][j] == 'a'){angle_x = i;angle_y = j;}}}}int check(int x,int y)/*越界判断*/ {int flag = 1;if(x < 0 || x > n-1 || y < 0 || y > m-1)flag = 0;return flag;}void BFS(){int x0,y0;/*next_x and next_y*/int h,r;/*队首队尾*/ /*由于救援可能有多个,所以以angel为起点,搜寻离她最近的救援队*/ h = 0;/*head and rear*/r = 1;q[1].x = angle_x,q[1].y = angle_y,q[1].time = 0;/*相当于队首入队,使初始节点进队*/while(h <= r)/*当队不为空队时*/{h++;/*出队*/ for(int i = 0 ; i < 4 ; i++){x0 = q[h].x + dx[i];y0 = q[h].y + dy[i];if(check(x0,y0) && vis[x0][y0] == 0 && maze[x0][y0] != '#'){r++;/*依次进队*/ q[r].x = x0;q[r].y = y0;vis[x0][y0] = 1;if(maze[x0][y0] == 'x')q[r].time = q[h].time + 2;else if(maze[x0][y0] == '.' || maze[x0][y0] == 'r')q[r].time = q[h].time + 1;}if(maze[x0][y0] == 'r')/*找到了最近的救援队*/{printf("%d\n",q[r].time);return ;}} } printf("Poor ANGEL has to stay in the prison all his life.\n");}int main(){while(cin>>n>>m){<span style="white-space:pre"></span>read();/*初始化迷宫,测试可以通过*/        <span style="white-space:pre"></span>BFS();}    return 0;}</span>
如此来看这其实是一道比较简单的题目,没有什么特别的技巧。
很多人讨论时说这是一个优先队列的题目,可是我这样写下来并没有觉得搜索过程中有体现“优先”这样的语句,莫名其妙的就AC了,说明我对着其中的道理还是不明白。也就是说,上边这段代码的思想其实是错的!
第二类:(c++中的STL带有优先队列,直接拿来用也很省时间。下面这份代码不是我写的,但是我感觉他的风格很不错,杭电亲测跑了46MS)
<span style="font-family:Microsoft YaHei;font-size:14px;">#include <iostream>#include <stdio.h>#include <string.h>#include <queue>#define N 201using namespace std;//优先队列解决,广度优先struct Persion{    int x,y;    int time;    friend bool operator < (const Persion &a,const Persion &b)    {        return a.time>b.time; //">" 返回队列中较小的元素;"< " 则返回队列中较大的元素    }};int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};char map[N][N];int visited[N][N];int m,n;int BFS(int x,int y){    priority_queue <Persion>q;    Persion current,next;    memset(visited,0,sizeof(visited));    current.x=x;    current.y=y;    current.time=0;    visited[current.x][current.y]=1;    q.push(current);    while(!q.empty())    {        current=q.top();        q.pop();        for(int i=0;i<4;i++)        {            next.x=current.x+dir[i][0];            next.y=current.y+dir[i][1];            if(next.x>=0&&next.x<n&&next.y>=0&&next.y<m&&map[next.x][next.y]!='#'&&!visited[next.x][next.y])            {                if(map[next.x][next.y]=='r')                    return current.time+1;                if(map[next.x][next.y]=='x')                    next.time=current.time+2;                else                    next.time=current.time+1;                visited[next.x][next.y]=1;                q.push(next);            }        }    }    return -1;}int main(){    int i,j;    Persion angle;    while(cin>>n>>m&&(m||n))    {        for(i=0;i<n;i++)            for(j=0;j<m;j++)            {                cin>>map[i][j];                if(map[i][j]=='a')                {                    angle.x=i;                    angle.y=j;                }            }         int time=BFS(angle.x,angle.y);         if(time==-1)            cout<<"Poor ANGEL has to stay in the prison all his life."<<endl;         else            cout<<time<<endl;    }    return 0;}</span>

PS:STL是一定要学的。不过我个人感觉还是先手动模拟一下队列和栈的一些操作会比较好,可以加深对这两种结构的理解。



0 0