题干:
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
解题报告:
其实记录路径的方法有很多,这里用的两个二维数组是其中一种,然而用栈表示其实也是大材小用了,只要dfs的时候多传两个参数就可以解决了 。还有一种方法就是定义一个结构体,并且可以顺便结构体中int x,y;char c;(或者int c) 这样可以顺便把这个地方的字符是‘ . ’ 还是0-9中的数字 可以表示出来了。
其实第一遍写还是很容易错的。但是比较良心的就是,特殊情况样例都给的比较清楚了,比如在(n,m)那个点有怪物的情况。这样我们依据样例就可以修正代码了。
AC代码:(这代码我保证我都不敢再看第二遍了。。。)
#include
using namespace std;
int n,m,curtime;
bool vis[105][105];
char maze[105][105];
int pathx[105][105];
int pathy[105][105];
int nx[4] = {0,1,0,-1};
int ny[4] = {1,0,-1,0};
stack xx,yy;
struct Node {
int x,y;
int time;
Node(){}
Node(int x,int y,int time):x(x),y(y),time(time){}
bool operator < (const Node b) const{
return time > b.time;
}
};
int bfs(int sx,int sy) {
memset(vis,0,sizeof vis);
priority_queue pq;
pq.push(Node(sx,sy,0));
while(!pq.empty()) {
Node cur = pq.top();pq.pop();
int tx,ty;
if(cur.x == n && cur.y == m) return cur.time;
for(int k = 0; k<4; k++) {
tx = cur.x + nx[k];
ty = cur.y + ny[k];
if(tx < 1 || tx > n || ty < 1 || ty > m) continue;
if(maze[tx][ty] == 'X' || vis[tx][ty] == 1) continue;
vis[tx][ty]=1;
if(maze[tx][ty] == '.') {
pq.push(Node(tx,ty,cur.time + 1));
pathx[tx][ty] = cur.x;
pathy[tx][ty] = cur.y;
}
else {
pq.push(Node(tx,ty,cur.time + 1 + maze[tx][ty] - '0'));
pathx[tx][ty] = cur.x;
pathy[tx][ty] = cur.y;
}
}
}
return -1;
}
void dfs(int x,int y) {
if(x == 1 && y == 1) {
printf("%ds:(0,0)->(%d,%d)\n",++curtime,xx.top()-1,yy.top()-1);
xx.pop();yy.pop();
return ;
}
dfs(pathx[x][y],pathy[x][y]);
if(x == n && y == m) {
if(maze[x][y]!='.'){
int all = maze[x][y] - '0';
while(all--)
printf("%ds:FIGHT AT (%d,%d)\n",++curtime,x-1,y-1);
}
return ;
}
if(maze[x][y] == '.') {
printf("%ds:(%d,%d)->(%d,%d)\n",++curtime,x-1,y-1,xx.top()-1,yy.top()-1);
xx.pop();yy.pop();
}
else {
int all = maze[x][y] - '0';
while(all--)
printf("%ds:FIGHT AT (%d,%d)\n",++curtime,x-1,y-1);
printf("%ds:(%d,%d)->(%d,%d)\n",++curtime,x-1,y-1,xx.top()-1,yy.top()-1);
xx.pop();yy.pop();
}
}
int main()
{
while(cin>>n>>m) {
while(xx.size()) xx.pop();
while(yy.size()) yy.pop();
for(int i = 1; i<=n; i++) {
scanf("%s",maze[i]+1);
}
int ans = bfs(1,1);
if(ans == -1) {
printf("God please help our poor hero.\nFINISH\n");continue;
}
printf("It takes %d seconds to reach the target position, let me show you the way.\n",ans);
curtime = 0;
int i=n,j=m;
while(i!=1 || j!=1) {//不能是&& !!!或者 while(!(i==1&&j==1))
xx.push(i);
yy.push(j);
//所以path用结构体存多好。。。
int tmpx = pathx[i][j];
int tmpy = pathy[i][j];
i=tmpx,j=tmpy;
}
// while(xx.size()){
// printf("%d ",xx.top());xx.pop();
// }
// printf("\n");
// while(yy.size()){
// printf("%d ",yy.top());yy.pop();
// }
dfs(n,m);
printf("FINISH\n");
}
return 0 ;
}
//23:31 - 24:10
总结:
写记录路径的时候的几个错误点:
第一:刚开始没有写56行左右的那个if(x==n && y==m) 后果:后来发现如果不写这个,也进入下面的printf,那么就会栈空的情况下xx.top(),肯定是会炸的。
第二 :刚开始改的时候直接if(x==n && y==m) return; 但是发现第二个样例不对,因为我的curtime还没到我的ans,所以我还需要判断是否在x==n && y==m这一点打架了,即这一点是否有怪物。而且还不能直接让他进入下面的else,因为我并不想让他输出printf("%ds:(%d,%d)->(%d,%d)\n",++curtime,x-1,y-1,xx.top()-1,yy.top()-1);这一句。所以无奈只能在if(x==n && y==m) return; 这里面做判断输出、
其实还有一种办法就是把FIGNT那个输出跟在“->”那种输出的后面,而不是先“->”输出这个 ,再输出FIGNT那个。类似于这种处理
int flag=bfs();
if(flag!=-1)
{
printf("It takes %d seconds to reach the target position, let me show you the way.\n",flag);
sec=1,x=y=0;
while(sec!=flag+1)
{
printf("%ds:(%d,%d)->(%d,%d)\n",sec++,x,y,map[x][y].nx,map[x][y].ny);
for(i=0;i