[ACM] hdu Ignatius and the Princess I

Ignatius and the Princess I

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 4   Accepted Submission(s) : 3
Special Judge

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

The Princess has been abducted by the BEelzebub feng5166, our hero Ignatius has to rescue our pretty Princess. Now he gets into feng5166's castle. The castle is a large labyrinth. To make the problem simply, we assume the labyrinth is a N*M two-dimensional array which left-top corner is (0,0) and right-bottom corner is (N-1,M-1). Ignatius enters at (0,0), and the door to feng5166's room is at (N-1,M-1), that is our target. There are some monsters in the castle, if Ignatius meet them, he has to kill them. Here is some rules:

1.Ignatius can only move in four directions(up, down, left, right), one step per second. A step is defined as follow: if current position is (x,y), after a step, Ignatius can only stand on (x-1,y), (x+1,y), (x,y-1) or (x,y+1).
2.The array is marked with some characters and numbers. We define them like this:
. : The place where Ignatius can walk on.
X : The place is a trap, Ignatius should not walk on it.
n : Here is a monster with n HP(1<=n<=9), if Ignatius walk on it, it takes him n seconds to kill the monster.

Your task is to give out the path which costs minimum seconds for Ignatius to reach target position. You may assume that the start position and the target position will never be a trap, and there will never be a monster at the start position.

Input

The input contains several test cases. Each test case starts with a line contains two numbers N and M(2<=N<=100,2<=M<=100) which indicate the size of the labyrinth. Then a N*M two-dimensional array follows, which describe the whole labyrinth. The input is terminated by the end of file. More details in the Sample Input.

Output

For each test case, you should output "God please help our poor hero." if Ignatius can't reach the target position, or you should output "It takes n seconds to reach the target position, let me show you the way."(n is the minimum seconds), and tell our hero the whole path. Output a line contains "FINISH" after each test case. If there are more than one path, any one is OK in this problem. More details in the Sample Output.

Sample Input

5 6
.XX.1.
..X.2.
2...X.
...XX.
XXXXX.
5 6
.XX.1.
..X.2.
2...X.
...XX.
XXXXX1
5 6
.XX...
..XX1.
2...X.
...XX.
XXXXX.

Sample Output

It takes 13 seconds to reach the target position, let me show you the way.
1s:(0,0)->(1,0)
2s:(1,0)->(1,1)
3s:(1,1)->(2,1)
4s:(2,1)->(2,2)
5s:(2,2)->(2,3)
6s:(2,3)->(1,3)
7s:(1,3)->(1,4)
8s:FIGHT AT (1,4)
9s:FIGHT AT (1,4)
10s:(1,4)->(1,5)
11s:(1,5)->(2,5)
12s:(2,5)->(3,5)
13s:(3,5)->(4,5)
FINISH
It takes 14 seconds to reach the target position, let me show you the way.
1s:(0,0)->(1,0)
2s:(1,0)->(1,1)
3s:(1,1)->(2,1)
4s:(2,1)->(2,2)
5s:(2,2)->(2,3)
6s:(2,3)->(1,3)
7s:(1,3)->(1,4)
8s:FIGHT AT (1,4)
9s:FIGHT AT (1,4)
10s:(1,4)->(1,5)
11s:(1,5)->(2,5)
12s:(2,5)->(3,5)
13s:(3,5)->(4,5)
14s:FIGHT AT (4,5)
FINISH
God please help our poor hero.
FINISH

Author

Ignatius.L

解题思路:用的bfs宽度优先搜索框架,本题的难点就是不光需要求出最短距离,还要打印出最短路径。昨天折腾了几个小时,用的传统的BFS,结果测试数据对,但提交一直Wa,在网上找了一些测试数据,结果没通过,发现了自己代码中的问题,要用到优先队列,于是我修改自己的代码把原来的队列换成优先队列,结果改完后测试数据和没改之前一模一样,一直到晚上睡觉前也没弄出来。今天早上早起又把代码仔细看了一遍,终于发现问题了,代码中优先队列的优先级竟然没有值,我说怎么用不用都一个样呢,又改了几个地方,提交竟然通过了。哎,看来,一道题目长时间做不出来还得先放一放沉淀一下。路径保存用二维数组,数组中的每个元素都是一个结构体类型的节点,里面起关键作用的就是fx,fy,前一个节点到当前节点的x增量和y增量,打印的时候用递归,回溯。

代码:

#include <iostream>
#include <queue>
#include <string.h>
using namespace std;
char map[102][102]; //地图
bool visited[102][102];//判断是否访问
int Min;

int dx[4]={0,0,-1,1};//方向控制
int dy[4]={-1,1,0,0};

struct node  //每个坐标是一个节点
{
    int x,y;//坐标位置
    int fx,fy;//增量比如前一个节点的x+1得到当前节点的x值,fx就为1 ,这在后面记录路径时用到
    int step;
    bool operator<(const node t)const{//后面用到了优先队列,对<进行重载,队列中step小的node在队头 top()。
        return step>t.step;
    }
};

node path[102][102];//用来记录路径,因为队列中的node都pop掉了,所以用一个数组来保存路径。

node a,b,c;//临时变量

int N,M;//地图大小

void getmap()//输入地图
{
    for(int i=0;i<N;++i)
        for(int j=0;j<M;++j)
        cin>>map[i][j];
}

void print(int n,int m)//打印路径,用递归的形式
{
    if(n==0&&m==0)
        return;
    print(n-path[n][m].fx,m-path[n][m].fy);
    if(map[n][m]>='1'&&map[n][m]<='9')
    {
        int t=map[n][m]-'0';
        cout<<path[n][m].step-t<<"s:"<<"("<<n-path[n][m].fx<<","<<m-path[n][m].fy<<")->("<<n<<","<<m<<")"<<endl;
        while(t)
        {
            cout<<path[n][m].step-t+1<<"s:"<<"FIGHT AT ("<<n<<","<<m<<")"<<endl;
            t--;
        }
    }
    else
        cout<<path[n][m].step<<"s:"<<"("<<n-path[n][m].fx<<","<<m-path[n][m].fy<<")->("<<n<<","<<m<<")"<<endl;
}

int main()
{
    while(cin>>N>>M)
    {
        memset(visited,0,sizeof(visited));
        priority_queue <node>q;//优先队列,优先级为node中的step大小
        getmap();
        a.x=0;
        a.y=0;
        a.fx=0;
        a.fy=0;
        a.step=0;
        visited[0][0]=1;//坐标(0,0)处开始
        q.push(a);
        path[0][0]=a;
        while(!q.empty())
        {
            b=q.top();
            q.pop();
            if(b.x==N-1&&b.y==M-1)
            {
                break;
            }
            for(int i=0;i<4;++i)
            {
                c.x=b.x+dx[i];
                c.y=b.y+dy[i];
                c.fx=dx[i];
                c.fy=dy[i];
                if(c.x>=0&&c.x<N&&c.y>=0&&c.y<M&&map[c.x][c.y]!='X'&&!visited[c.x][c.y])
                {
                    path[c.x][c.y]=c;
                    visited[c.x][c.y]=1;//已访问
                    if(map[c.x][c.y]>='1'&&map[c.x][c.y]<='9')
                       {
                           path[c.x][c.y].step=path[b.x][b.y].step+map[c.x][c.y]-'0'+1;
                           c.step=b.step+map[c.x][c.y]-'0'+1;//这条语句很重要啊,一开始就是忘了写这条语句,结果优先队列使用和不使用一个样,队列中的node的step起关键作用,不能忘
                       }
                    else
                       {
                           path[c.x][c.y].step=path[b.x][b.y].step+1;
                           c.step=b.step+1;
                       }
                       q.push(c);//注意这句不能提前写,要保证,节点c中德各个元素都有值,x,y,fx,fy,step
                }
            }
        }
       /* for(int i=0;i<N;++i)
        {
            for(int j=0;j<M;j++)
                cout<<step[i][j]<<" ";
            cout<<endl;
        }*/ //用来测试步数
        if(visited[N-1][M-1])//如果目的地坐标(N-1,M-1)被访问了,说明可以到达目的地
        {
            cout<<"It takes "<<path[N-1][M-1].step<<" seconds to reach the target position, let me show you the way."<<endl;
            print(N-1,M-1);
        }
        else
            cout<<"God please help our poor hero."<<endl;
        cout<<"FINISH"<<endl;
    }
    return 0;
}

运行截图:


上面是题目上给的测试数据,但是很坑啊,你以为代码写对了,其实没对,我就掉进坑里了,一直Wrong Answer于是在网上又找测试数据,发现下面一组,

5 7
...X...
.X.X.X.
.X...X.
.XXXXX.
....9..

正确结果应该是14s,我原来的代码结果是19s,所以一直错。修改后的代码运行结果:



posted @ 2014-01-18 09:04  同学少年  阅读(153)  评论(0编辑  收藏  举报