Ignatius and the Princess I
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 16269 Accepted Submission(s): 5164
Special Judge
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
题意:从(0,0)到(n-1,m-1)‘.‘代表路,‘X‘代表障碍,‘n’带表怪物血量,打过就可以过了,消耗时间n
题目思想:
广搜(bfs)
这是我第一次接触到广搜,就大致查询了一下广搜,再结合以前的深搜,总结如下:
深搜是与栈有关:
拿树来做例子,深搜是把树的某个分支进行到底再查找另一个分支,直到满足条件结束或者分支找完结束
再说说与栈的关系:栈,先进后出,即把树的根放在栈底上面的栈内元素就可以依次换元,就可以遍历完整个结构
再说说在图中:即从起始点走到终点再返回一步再往下走,直到满足条件或者遍历完成
广搜是与队有关:
拿树来做例子,广搜一层一层地遍历,就像树一样,一层一层展开的枝繁叶茂
再说说与队列的关系:队列是先进先出,即我们拿到一个节点可以把他所有的子节点全部进队,而总是把一层的节点遍历完成才会进行到下一层
再说说在图中:从起点开始一层一层向外延伸(类似于一个墨滴在纸上扩散的视觉效果),直到满足条件或者遍历完成
AC代码:
#include<iostream> #include<queue> #include<stack> #include<stdlib.h> #include<iomanip> using namespace std; int n,m; char map[101][101]; typedef struct point { int x,y,step,time;//step用于记录到此点的方向,step=1,2,3,4 ->上下左右 }*prt;//因为队中元素需要修改,用指针 prt t[100][100]; bool cheak(int x,int y)//判断是否可达 { if(x<0||y<0||x>=n||y>=m||map[x][y]=='X') return false; return true; } //广搜遍历所有可能 void bfs() { queue<prt> Q;//因为队中元素需要修改,用指针 prt corrent; int x,y,k,i; bool flag; t[0][0]->time=0;//出发点时间置0 Q.push(t[0][0]);//出发点进队 while(!Q.empty()) { corrent=Q.front(); x=corrent->x; y=corrent->y; Q.pop(); //对于上下左右四个点进行查看: // 如果可以达到,并且从当前点走过去比以前方式到达他的时间小 // 就将这个点进队 // 这里既有初始情况到达,也有事后修改,并且修改需要修改以后所有点,所以也需要进队(即最后样例所给) if(cheak(x-1,y)&&corrent->time+map[x-1][y]-'0'+1<t[x-1][y]->time) { t[x-1][y]->time=corrent->time+map[x-1][y]-'0'+1; Q.push(t[x-1][y]); t[x-1][y]->step=4; } if(cheak(x+1,y)&&corrent->time+map[x+1][y]-'0'+1<t[x+1][y]->time) { t[x+1][y]->time=corrent->time+map[x+1][y]-'0'+1; Q.push(t[x+1][y]); t[x+1][y]->step=3; } if(cheak(x,y-1)&&corrent->time+map[x][y-1]-'0'+1<t[x][y-1]->time) { t[x][y-1]->time=corrent->time+map[x][y-1]-'0'+1; Q.push(t[x][y-1]); t[x][y-1]->step=2; } if(cheak(x,y+1)&&corrent->time+map[x][y+1]-'0'+1<t[x][y+1]->time) { t[x][y+1]->time=corrent->time+map[x][y+1]-'0'+1; Q.push(t[x][y+1]); t[x][y+1]->step=1; } } } int main() { int k,i,order,time; while(cin>>n>>m) { for(k=0;k<n;k++) for(i=0;i<m;i++) { t[k][i]=new point; cin>>map[k][i]; if(map[k][i]=='.') map[k][i]='0'; t[k][i]->x=k; t[k][i]->y=i; t[k][i]->time=10000000; t[k][i]->step=-1; } t[0][0]->step=1; bfs(); if(t[n-1][m-1]->time<10000000)//如果可以到达目的地 { cout<<"It takes "<<t[n-1][m-1]->time<<" seconds to reach the target position, let me show you the way."<<endl; stack<point> S; point p,last; k=n-1; i=m-1; while(k>=0&&i>=0)//由最后点按照每一点的step找到路线 ,找到的上一点都入栈 { p.x=k; p.y=i; S.push(p); order=t[k][i]->step; if(order==4) k+=1; if(order==3) k-=1; if(order==2) i+=1; if(order==1) i-=1; } p=S.top(); S.pop(); time=1; while(!S.empty())//输出栈 { last=p; p=S.top(); cout<<(time++)<<"s:("<<last.x<<","<<last.y<<")->("<<p.x<<","<<p.y<<")"<<endl; for(k=0;k<map[p.x][p.y]-'0';k++)//输出在某点打怪消耗时间 cout<<(time++)<<"s:FIGHT AT ("<<p.x<<","<<p.y<<")"<<endl; S.pop(); } } else cout<<"God please help our poor hero."<<endl; cout<<"FINISH"<<endl; for(k=0;k<n;k++)//删除申请空间 for(i=0;i<m;i++) delete t[k][i]; } return 0; }
测试样例:
5 6
.XX.1.
..X.9.
2...X.
...XX.
XXXXX.