Ignatius and the Princess I
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 10541 Accepted Submission(s): 3205
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.
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
Recommend
目录:
一开始不知道这道题要用广搜bfs做,上来直接用了深搜dfs(广搜实在是还不会用),加起来做了近4个小时,最后提交给了我一个超时……
对着一位同样用dfs做的却AC(耗时900+MS)的大神的代码(博客地址:http://blog.csdn.net/qhc_20130731/article/details/9078149)改了改,到后来代码直接看不懂了!
贴上我的代码,愿有看到的筒靴帮一把!感激不尽!
测试数据正确,提交超时。
1 #include <iostream>
2 #include <stdio.h>
3 #include <string.h>
4 using namespace std;
5 struct Way{
6 int x;
7 int y;
8 bool ism;
9 }way[200]; //存储每一秒走到的位置,及有没有怪物
10 char maze[100][100];
11 bool isv[100][100];
12 int dx[4]={0,1,0,-1};
13 int dy[4]={1,0,-1,0};
14 int curx,cury;
15 int endx,endy;
16 int N,M;
17 int _min;
18 int dfs(int curx,int cury,int s) //当前的位置以及走到这个位置用的时间(秒)和方向
19 {
20 int n=0;
21 if(curx==N-1 && cury==M-1){
22 //到达终点
23 _min=s;
24 if('1'<=maze[curx][cury] && maze[curx][cury]<='9'){
25 //如果当前位置有怪物
26 int t; //怪物的HP
27 t=maze[curx][cury]-'0';
28 for(int i=0;i<=t;i++){
29 way[s-i].x=curx;
30 way[s-i].y=cury;
31 way[s-i].ism=true;
32 }
33 }
34 else{
35 //当前位置没有怪物
36 way[s].x=curx;
37 way[s].y=cury;
38 way[s].ism=false;
39 }
40 return s;
41 }
42 //没有走到终点的时候
43 for(int i=0;i<4;i++){
44 int nx = curx+dx[i];
45 int ny = cury+dy[i];
46 if(0<=nx && nx<=N-1 && 0<=ny && ny<=M-1 //如果没有越界
47 && maze[nx][ny]!='X' //下一步没有陷阱
48 && !isv[nx][ny] //下一步没走过
49 ){
50 int t; //有怪物的话存储怪物的HP,否则为1
51 if('1'<=maze[nx][ny] && maze[nx][ny]<='9'){
52 t=int(maze[nx][ny]-'0')+1;
53 }
54 else{
55 t=1;
56 }
57 if(s+t>=_min) continue; //再次剪枝
58 isv[nx][ny]=true;
59 int tt;
60 if( tt=dfs(nx,ny,s+t) ){
61 //找到最短路
62 n=tt;
63 way[s].x=curx;
64 way[s].y=cury;
65 way[s].ism=false;
66 if('1'<=maze[curx][cury] && maze[curx][cury]<='9'){
67 //如果当前位置有怪物
68 int t; //怪物的HP
69 t=maze[curx][cury]-'0';
70 for(int i=1;i<=t;i++){
71 way[s-i].x=curx;
72 way[s-i].y=cury;
73 way[s-i].ism=true;
74 }
75 }
76 }
77 isv[nx][ny]=false;
78 }
79 }
80 return n;
81 }
82 int main()
83 {
84 while(scanf("%d%d",&N,&M)!=EOF){ //开始一个新的地图
85 getchar();
86 memset(isv,0,sizeof(isv)); //初始化
87 _min=9999999;
88 curx=0,cury=0; //初始化开始、终点位置
89 endx=N-1,endy=M-1;
90 for(int i=0;i<N;i++){
91 for(int j=0;j<M;j++){
92 scanf("%c",&maze[i][j]);
93 }
94 getchar();
95 }
96 int n; //如果能走到终点的话,接收最短步数
97 isv[0][0]=true;
98 n=dfs(curx,cury,0);
99 if(n){
100 //能走
101 printf("It takes %d seconds to reach the target position, let me show you the way.\n",n);
102 for(int i=0;i<n;i++){
103 if(way[i].ism){
104 //如果有怪物
105 printf("%ds:FIGHT AT (%d,%d)\n",i+1,way[i].x,way[i].y);
106 }
107 else {
108 printf("%ds:(%d,%d)->(%d,%d)\n",i+1,way[i].x,way[i].y,way[i+1].x,way[i+1].y);
109 }
110 }
111 }
112 else{
113 //走不到终点
114 printf("God please help our poor hero.\n");
115 }
116 printf("FINISH\n");
117 }
118 return 0;
119 }
重写了这道题,用广搜方法终于提交AC了。
bfs广搜题。
这道题着实费了我不少力气,写了3个小时,原因是这道题在bfs基本框架的基础上改动比较大,对刚刚熟悉广搜做法的我来说有些吃力。而且中间由于思路想的不对,走了弯路,花费了不少时间修改。事实证明,思路很重要,想的有一点偏差,就要付出双倍时间的代价为这点偏差买单。另外,程序实现能力还需要提高,有些思路不是想不到,而是觉得自己实现不了而下意识的规避了。如果什么程序实现能力变强了,思考问题就会用这种语言去想,等到真正去实现的时候,自然就水到渠成。
好了扯远了,回到这道题,题目大意为:骑士(地图左上角)要去救公主(地图右下角),而他们之间(地图上)有3种物体,‘.’为路,可以通过;‘X’为墙,不能通过;'1'~'9'数字为怪物的血量num。骑士遇到怪物,要停留num秒,求骑士能否到达公主的位置,如果能到达,输出最短路径的长度,并输出路径,如果不能到,输出特定语句。
思路是bfs中遇到怪物的时候节点位置(x,y)不作处理,而只将当前节点步数(step)加1,将它重新入队,同时怪物血量-1(注意这里要对备用地图处理),直到减为0才能通过,这期间,该点一直在怪物位置。关于路径的处理,广搜的时候记录下路径,退出广搜后从终点处开始还原路径。之后输出路径。
难点是遇到怪物时的处理和路径的还原。
1 #include <iostream>
2 #include <string.h>
3 #include <queue>
4 using namespace std;
5 char a[101][101]; //记录地图
6 char b[101][101]; //备用地图,用以修改
7 int isv[101][101]; //记录访问过没有
8 int way[101][101]; //记录路径
9 int dx[4] = {0,1,0,-1};
10 int dy[4] = {1,0,-1,0};
11 int N,M;
12 struct NODE{
13 int x;
14 int y;
15 int step;
16 };
17 bool judge(int x,int y)
18 {
19 if( x<1 || y<1 || x>N || y>M ) //出界
20 return 1;
21 if( isv[x][y] ) //走过
22 return 1;
23 if( a[x][y]=='X' ) //遇到墙
24 return 1;
25 return 0;
26 }
27 int bfs(int x,int y) //返回到达终点的时间(包括在终点停留的时间)
28 {
29 for(int i=1;i<=N;i++)
30 for(int j=1;j<=M;j++)
31 b[i][j] = a[i][j];
32 queue <NODE> q;
33 NODE cur,next;
34 cur.x = x;
35 cur.y = y;
36 cur.step = 0;
37 q.push(cur); //第一个节点入队
38 while(!q.empty()){
39 cur = q.front();
40 q.pop(); //队首出队
41 if( cur.x==N && cur.y==M ){
42 int num = 0;
43 if('1'<=b[cur.x][cur.y] && b[cur.x][cur.y]<='9')
44 num = b[cur.x][cur.y] - '0';
45 return cur.step + num;
46 }
47 if('1'<=b[cur.x][cur.y] && b[cur.x][cur.y]<='9'){ //遇到怪物,step+1,位置不变,入队
48 next.x = cur.x;
49 next.y = cur.y;
50 next.step = cur.step + 1;
51 q.push(next);
52 if(b[cur.x][cur.y]=='1')
53 b[cur.x][cur.y] = '.';
54 b[cur.x][cur.y]--;
55 continue;
56 }
57 for(int i=0;i<4;i++){
58 int nx = cur.x + dx[i];
59 int ny = cur.y + dy[i];
60 if(judge(nx,ny)) //判定
61 continue;
62 //可以走
63 next.x = nx;
64 next.y = ny;
65 way[nx][ny] = i; //记录路径
66 isv[nx][ny] = true; //记录访问过
67 next.step = cur.step + 1;
68 q.push(next);
69 }
70 }
71 return 0;
72 }
73 int main()
74 {
75 while(cin>>N>>M){
76 for(int i=1;i<=N;i++)
77 for(int j=1;j<=M;j++)
78 cin>>a[i][j];
79 memset(isv,0,sizeof(isv));
80 isv[1][1] = true;
81 int step = bfs(1,1);
82 if(step){ //到达终点
83 NODE way_node[10001];
84 int cx=N,cy=M;
85 for(int i=step;i>=0;i--){ //根据way[][]还原路径
86 way_node[i].x = cx;
87 way_node[i].y = cy;
88 int num=0;
89 if('1'<=a[cx][cy] && a[cx][cy]<='9') //如果该位置有怪物
90 num = a[cx][cy] - '0';
91 for(int j=num;j>=1;j--){
92 way_node[i-j].x = cx;
93 way_node[i-j].y = cy;
94 }
95 if(num){
96 i-=num;
97 }
98 switch(way[cx][cy]){ //没有怪物则继续还原路径
99 case 0:cy--;break;
100 case 1:cx--;break;
101 case 2:cy++;break;
102 case 3:cx++;break;
103 default:break;
104 }
105 }
106 //输出结果
107 cout<<"It takes "<<step<<" seconds to reach the target position, let me show you the way."<<endl;
108 for(int i=1;i<=step;i++){
109 cout<<i<<"s:("<<way_node[i-1].x-1<<','<<way_node[i-1].y-1<<")->("<<way_node[i].x-1<<','<<way_node[i].y-1<<')'<<endl;
110 cx = way_node[i].x;
111 cy = way_node[i].y;
112 if('1'<=a[cx][cy] && a[cx][cy]<='9'){
113 int num = a[cx][cy] - '0';
114 for(int j=1;j<=num;j++)
115 cout<<i+j<<"s:FIGHT AT ("<<way_node[i].x-1<<','<<way_node[i].y-1<<')'<<endl;
116 i += num;
117 }
118 }
119 cout<<"FINISH"<<endl;
120 }
121 else{ //没有到达终点
122 cout<<"God please help our poor hero."<<endl;
123 cout<<"FINISH"<<endl;
124 }
125 }
126 return 0;
127 }
受同学启发,用“优先队列”又写了一遍,顺便学习了一下优先队列的使用。
思路和上面是基本相同的,只不过遇到怪物时的处理用优先队列简化了许多,优先队列不会用的筒靴可以参考下面的链接:
另外给出一位同样用优先队列实现的博客链接,不过人家是0MS AC,我是31MS AC,有差距啊!
下面是我用优先队列做的代码:
1 #include <iostream>
2 #include <string.h>
3 #include <queue>
4 using namespace std;
5 char a[101][101];
6 char isv[101][101]; //记录访问过没有
7 int dir[101][101]; //记录每一个节点的来路方向,即整个地图遍历的顺序
8 int dx[4] = {0,1,0,-1};
9 int dy[4] = {1,0,-1,0};
10 int N,M;
11 struct NODE{
12 int x;
13 int y;
14 int step;
15 friend bool operator < (NODE n1,NODE n2) //自定义优先级。在优先队列中,优先级高的元素先出队列。
16 {
17 return n1.step > n2.step; //通过题意可知 step 小的优先级高,需要先出队。
18 }
19 };
20 bool judge(int x,int y)
21 {
22 if( x<1 || y<1 || x>N || y>M )
23 return 1;
24 if( isv[x][y] )
25 return 1;
26 if( a[x][y]=='X' )
27 return 1;
28 return 0;
29 }
30 int bfs(int x,int y) //返回从(x,y)开始广搜,到右下角的最短步数,如果无法到达右下角,返回0
31 {
32 priority_queue <NODE> q; //定义一个优先队列
33 NODE cur,next;
34 cur.x = x;
35 cur.y = y;
36 cur.step = 0;
37 q.push(cur); //第一个元素入队
38 while(!q.empty()){
39 cur = q.top(); //队首出队,注意不是front()
40 q.pop();
41 if(cur.x==N && cur.y==M){ //到终点
42 return cur.step;
43 }
44 for(int i=0;i<4;i++){
45 int nx = cur.x + dx[i];
46 int ny = cur.y + dy[i];
47 if( judge(nx,ny) ) //判定
48 continue;
49 //可以走
50 next.x = nx;
51 next.y = ny;
52 isv[nx][ny] = true;
53 dir[nx][ny] = i;
54 if( '1'<=a[nx][ny] && a[nx][ny]<='9' ){ //这一步有怪物
55 int hp = a[nx][ny] - '0';
56 next.step = cur.step + hp + 1;
57 }
58 else //这一步没有怪物
59 next.step = cur.step + 1;
60 q.push(next);
61 }
62 }
63 return 0;
64 }
65 int main()
66 {
67 while(cin>>N>>M){
68 for(int i=1;i<=N;i++)
69 for(int j=1;j<=M;j++)
70 cin>>a[i][j];
71 memset(isv,0,sizeof(isv));
72 isv[1][1] = true;
73 int step = bfs(1,1);
74 if(step){ //step有值,能够到达终点
75 //还原路径
76 NODE way[10001];
77 int cx=N,cy=M;
78 for(int i=step;i>=0;i--){
79 way[i].x = cx;
80 way[i].y = cy;
81 if('1'<=a[cx][cy] && a[cx][cy]<='9'){ //当前位置有怪物
82 int hp = a[cx][cy] - '0';
83 for(int j=1;j<=hp;j++){
84 way[i-j].x = cx;
85 way[i-j].y = cy;
86 }
87 i -= hp;
88 }
89 switch(dir[cx][cy]){
90 case 0:cy--;break;
91 case 1:cx--;break;
92 case 2:cy++;break;
93 case 3:cx++;break;
94 default:break;
95 }
96 }
97 //输出结果
98 cout<<"It takes "<<step<<" seconds to reach the target position, let me show you the way."<<endl;
99 for(int i = 1;i<=step;i++){
100 cout<<i<<"s:("<<way[i-1].x-1<<','<<way[i-1].y-1<<")->("<<way[i].x-1<<','<<way[i].y-1<<')'<<endl;
101 if( '1'<=a[way[i].x][way[i].y] && a[way[i].x][way[i].y]<='9' ){ //如果有怪物
102 int hp = a[way[i].x][way[i].y] - '0';
103 for(int j=1;j<=hp;j++)
104 cout<<i+j<<"s:FIGHT AT ("<<way[i+j].x-1<<','<<way[i+j].y-1<<')'<<endl;
105 i+=hp;
106 }
107 }
108 }
109 else{ //step为0,说明不能到达终点
110 cout<<"God please help our poor hero."<<endl;
111 }
112 cout<<"FINISH"<<endl;
113 }
114 return 0;
115 }
Freecode : www.cnblogs.com/yym2013