Ignatius and the Princess I

Ignatius and the Princess I

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.

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.

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.

输入:

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.

输出:

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

思路:

从(0,0)点出发抵达(N-1,M-1)点。‘X’表示此点是陷阱不可走,’.'表示此点可走,'n’表示此点有怪物n为怪物血量,需要n秒才能击败怪物(这里需要注意是击败怪物需要多少秒,而抵达此点需要的时间依然要加上)。

一个bfs题,最难的地方在于如何记录路径,我是用的方法是借助一个数组ditu[105][105]去存储(这里在代码里解释把),还有这题要求如果你在此点与怪物战斗几秒需要输出FIGHT AT [X,Y]几次,这个可以借助此点的数据去处理。这题因为加了bool数组去标记点,发现提交总是内存超限(也不知道怎么回事),所以选择经过这个点时把这个点变换一下。

如何通过递归寻找上一个点的坐标

在这里插入图片描述
假定0为向右,1为向下,2为向左,3为向上。
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
讲一下如何通过回溯寻找上点坐标,假定从(2,2)点出发抵达(2,3)点,则把ditu[2][3]这个点的数据变为0,在借助x-dx[ditu[2][3]],y-dy[ditu[2][3]],即可得到上一个点的坐标。

代码

#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
struct Inof
{
	int x;
	int y;
	int num;
	friend operator < (Inof a,Inof b)   //优先级高的优先出列
	{
	    return a.num > b.num;
	}
};
int N,M,d=0;
char map[105][105];    
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int ditu[105][105];   //用来通过递归寻找上一点
int pan[105][2];   //用来储存此点坐标
bool panding(int x , int y)
{
    if(x>(N-1)||y>(M-1)||x<0||y<0)
        return 1;
    if(map[x][y]=='X')
        return 1;
//这里是因为用bool型判断内存超限,因为题设说怪物血量不会超过9,
//所以干脆的判断是否大于10。
    if(map[x][y]-'0'>10)  
        return 1;
    return 0;
}
int bfs()
{
    Inof cur,next;
    priority_queue<Inof> a;
    cur.x=0,cur.y=0,cur.num=0;
    map[0][0]='X';   //经过的时候把此点变为'X',代表已经走过
    a.push(cur);
    while(!a.empty())
    {
        cur = a.top();
        a.pop();
        if(cur.x == N-1 && cur.y == M-1)   //抵达终点
        {
            return cur.num;
        }
        for(int i=0 ; i<4 ; i++)
        {
            int x = cur.x + dx[i];
            int y = cur.y + dy[i];
            if(panding(x,y))
                continue;
            next.x = x;
            next.y = y;
            ditu[x][y]=i;
            if(map[x][y]=='.')
            {
               next.num = cur.num + 1;
               map[x][y] = 'X';
            }
            else    //如果此点有怪物
            {
                 next.num = cur.num + map[x][y]-'0' + 1;  //步数增加怪物血量加上一步需要的时间
                 map[x][y] = map[x][y]+10;   //标记此点,题设说怪物血量最多9点,所以+10代表已标记
            }
            a.push(next);
        }
    }
    return -1;
}
void huisu(int x,int y)   //回溯去寻找路径
{
    //这里有待改善,因为这样并不会存储(0,0)点
    //所以在输出时需要加上(0,0)点
    if(x==0 && y==0)
        return ;
    huisu(x-dx[ditu[x][y]],y-dy[ditu[x][y]]);
    pan[d][0]=x;   //记录坐标
    pan[d][1]=y;   //记录坐标
    d++;
}
int main()
{
    while(cin >> N >> M)
    {
        for(int i=0;i<N;i++)
        {
            getchar();
            for(int j=0;j<M;j++)
                 scanf("%c",&map[i][j]);
        }
        int t = bfs();
        if(t!=-1)
        cout << "It takes " << t << " seconds to reach the target position, let me show you the way." << endl;
        else
        cout << "God please help our poor hero." << endl;
        huisu(N-1,M-1);
        if(t!=-1)
        {
            // (0,0)点单独输出
            cout << "1s:" << "(0,0)->" << '(' << pan[0][0] << ',' << pan[0][1] << ')' << endl;
            int q=2;
            int i;
            for(i=0;i<d-1;i++)
            {
                //如果此点数据并不是'X',则代表此点存在怪物
               if(map[pan[i][0]][pan[i][1]]!='X')
                {
                    //怪物血量为多少则输出多少次,由于标记时+10,所以这里需要-10。
                    for(int j=0;j<map[pan[i][0]][pan[i][1]]-'0'-10;j++)
                    {
                        cout << q << "s:" << "FIGHT AT " << '(' << pan[i][0] << ',' << pan[i][1] << ')' << endl;
                        q++;
                    }
                }
                cout << q << "s:" << '(' << pan[i][0] << ',' << pan[i][1] << ')' << "->" << '(' << pan[i+1][0] << ',' << pan[i+1][1] << ')' << endl;
                q++;
            }
            //由于(N-1,M-1)点可能是怪物,所以判定一下
            if(map[pan[i][0]][pan[i][1]]!='X')
            {
                 for(int j=0;j<map[pan[i][0]][pan[i][1]]-'0'-10;j++)
                    {
                        cout << q << "s:" << "FIGHT AT " << '(' << pan[i][0] << ',' << pan[i][1] << ')' << endl;
                        q++;
                    }
            }
        }
        cout << "FINISH" <<endl;
        d=0;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值