hdu 1026 Ignatius and the Princess I

hdu   1026   Ignatius and the Princess I        题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1026 

题目大意:经典二维迷宫问题,魔王、公主与勇士的故事,这不是魔塔么???!!!

题目分析:又是要求输出路径的BFS,还打小怪兽,不过不怕,poj3984打印过路径,hdu1242也打过小怪兽,这道题做起来就颇得心应手了。假设读者已经完全熟悉BFS的基本方法,下面就说一下两个难点。

(1)怎么打小怪兽:可以用优先队列,加入一个点的时候把这个点的怪兽血量加到步数里,把步数多的排到后面;其实根本不需要用优先队列,普通队列一样可以解决这个问题,只需要在扩增时把还有活怪兽的点怪兽血量减一,步数加一,重新入队,直到怪死了才允许往其他点上走。

(2)怎么记录路径:定义一个pre数组,大小同map,记录每个点的前驱,遍历时当一个点(first)找到下一个可走点(next)时就把下一个点对应位置的pre设为first,再稍注意一下边界,就能完美地记录下一条路径了。记录下来还不够,因为它是倒着的,很容易想到用栈,那么递归也可以(其实一维数组就能解决这个问题)。

至此全部问题分析完毕,AC代码奉上。

code:

#include<cstdio>
#include<cstring>
#include<queue>
#include<stack>
using namespace std;
struct node
{
	int x,y,step,hp;
	friend bool operator<(node n1,node n2)
	{
		return n2.step<n1.step;
	}
}pre[111][111];
int map[111][111],dir[4][2]={1,0,-1,0,0,1,0,-1},m,n;
bool vis[111][111];
int temp;
void P(node p)
{
	if(p.x==0&&p.y==0)	return ;
	P(pre[p.x][p.y]);
	printf("%ds:(%d,%d)->(%d,%d)\n",temp++,pre[p.x][p.y].x,pre[p.x][p.y].y,p.x,p.y);
	while(map[p.x][p.y]--)	printf("%ds:FIGHT AT (%d,%d)\n",temp++,p.x,p.y);
}
bool judge(int x,int y)
{
	return x<m&&y<n&&x>=0&&y>=0&&map[x][y]!=-1&&!vis[x][y];
}
node bfs()
{
	priority_queue<node>q;
	node first,next;
	first.x=0,first.y=0,first.step=0,first.hp=0;
	q.push(first);
	while(!q.empty())
	{
		first=q.top();
		q.pop();
		if(first.x==m-1&&first.y==n-1)return first;
		for(int i=0;i<4;i++)
		{
			next.x=first.x+dir[i][0];
			next.y=first.y+dir[i][1];
			if(judge(next.x,next.y))
			{
				next.step=first.step+1+map[next.x][next.y];
				q.push(next);
				vis[next.x][next.y]=true;
				pre[next.x][next.y]=first;
			}
		}
	}
	return first;
}
int main()
{
	int i,j;
	char s[111];
	while(scanf("%d%d",&m,&n)!=EOF)
	{
		memset(vis,false,sizeof(vis));
		for(i=0;i<m;i++)
		{
			scanf("%s",s);
			for(j=0;j<=n;j++)
			{
				switch(s[j])
				{
					case'.':map[i][j]=0;break;//平地
					case'X':map[i][j]=-1;break;//墙
					default:map[i][j]=s[j]-'0';//有怪存血
				}
			}
		}
		map[0][0]=0;
		vis[0][0]=true;
		node p=bfs();
		if(!vis[m-1][n-1])printf("God please help our poor hero.\n");
		else
		{
			printf("It takes %d seconds to reach the target position, let me show you the way.\n",p.step);
			temp=1;
			P(p);//输出用的递归
		}
		printf("FINISH\n");
	}
	return 0;
}
PS:两天A了这一道题,总共交了20遍,吐血了有木有……能改的地方都改了,连不可能出现的数据我都测试了,最后发现问题出在路径输出上,sad……

附wrong码,祭奠一下逝去的两天:

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
struct node
{
	int x,y,step,hp;
}path[110000],pre[110][110];
int map[110][110],dir[4][2]={1,0,-1,0,0,1,0,-1},m,n;
bool vis[110][110];
bool judge(int x,int y)
{
	return x<m&&y<n&&x>=0&&y>=0&&map[x][y]!=-1&&!vis[x][y];
}
node bfs()
{
	queue<node>q;
	node first,next;
	first.x=0,first.y=0,first.step=0,first.hp=0;
	q.push(first);
	while(!q.empty())
	{
		first=q.front();
		q.pop();
		if(map[first.x][first.y]>0)
		{
			first.hp++;
			first.step++;
			map[first.x][first.y]--;
			q.push(first);
			continue;
		}
		for(int i=0;i<4;i++)
		{
			next.x=first.x+dir[i][0];
			next.y=first.y+dir[i][1];
			if(judge(next.x,next.y))
			{
				next.step=first.step+1;
				next.hp=0;
				q.push(next);
				vis[next.x][next.y]=true;
				pre[next.x][next.y]=first;
				if(next.x==m-1&&next.y==n-1&&!map[next.x][next.y])return next;
			}
		}
	}
	return first;
}
int main()
{
	int i,j;
	char s[110];
	while(scanf("%d%d",&m,&n)!=EOF)
	{
		memset(vis,false,sizeof(vis));
		for(i=0;i<m;i++)
		{
			scanf("%s",s);
			for(j=0;j<=n;j++)
			{
				switch(s[j])
				{
					case'.':map[i][j]=0;break;//??? 
					case'X':map[i][j]=-1;break;//? 
					default:map[i][j]=s[j]-'0';//?й??? 
				}
			}
		}
		map[0][0]=0;
		vis[0][0]=true;
		node p=bfs();
		int step=p.step;
		if(!vis[m-1][n-1])printf("God please help our poor hero.\n");
		else
		{
			printf("It takes %d seconds to reach the target position, let me show you the way.\n",p.step);
			path[p.step]=p;
			while(p.x!=0||p.y!=0||p.step)
			{
				if(pre[p.x][p.y].step==p.step-1)p=pre[p.x][p.y];
				else p.step--;
				path[p.step]=p;
			}
			for(i=0;i<step;i++)
			{
				printf("%ds:",i+1);
				if(path[i].x==path[i+1].x&&path[i].y==path[i+1].y)printf("FIGHT AT (%d,%d)\n",path[i].x,path[i].y);
				else
				printf("(%d,%d)->(%d,%d)\n",path[i].x,path[i].y,path[i+1].x,path[i+1].y);
			}
		}
		printf("FINISH\n");
	}
	return 0;
}/*后几组是自己想的,希望给wrong的同学一点帮助
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.
5 6
1XX.1.
..X.2.
2...X.
...XX.
XXXXX1
5 6
1XX.1.
.1X12.
2.1.X4
...XX9
XXXXX1
5 6
1XX.1.
11X121
2111X4
...XX1
XXXXX1
5 6
......
......
......
......
......
5 6
.9...9
.9.9.9
.9.9.9
.9.9.9
X..9..
*/
上面的代码没用优先队列,而且是用数组存的结果。下面是个改成栈存的版本,感觉离真相近一点了没?

#include<cstdio>
#include<cstring>
#include<queue>
#include<stack>
using namespace std;
struct node
{
	int x,y,step,hp;
	friend bool operator<(node n1,node n2)
	{
		return n2.step<n1.step;
	}
}path[110000],pre[110][110];
int map[110][110],dir[4][2]={1,0,-1,0,0,1,0,-1},m,n;
bool vis[110][110];
bool judge(int x,int y)
{
	return x<m&&y<n&&x>=0&&y>=0&&map[x][y]!=-1&&!vis[x][y];
}
node bfs()
{
	priority_queue<node>q;
	node first,next;
	first.x=0,first.y=0,first.step=0,first.hp=0;
	q.push(first);
	while(!q.empty())
	{
		first=q.top();
		q.pop();
		if(first.x==m-1&&first.y==n-1)return first;
		for(int i=0;i<4;i++)
		{
			next.x=first.x+dir[i][0];
			next.y=first.y+dir[i][1];
			if(judge(next.x,next.y))
			{
				next.step=first.step+1+map[next.x][next.y];
				q.push(next);
				vis[next.x][next.y]=true;
				pre[next.x][next.y]=first;
			}
		}
	}
	return first;
}
int main()
{
	int i,j;
	char s[110];
	while(scanf("%d%d",&m,&n)!=EOF)
	{
		memset(vis,false,sizeof(vis));
		for(i=0;i<m;i++)
		{
			scanf("%s",s);
			for(j=0;j<=n;j++)
			{
				switch(s[j])
				{
					case'.':map[i][j]=0;break;
					case'X':map[i][j]=-1;break;
					default:map[i][j]=s[j]-'0';
				}
			}
		}
		map[0][0]=0;
		vis[0][0]=true;
		node p=bfs();
		int step=p.step,t=1;
		if(!vis[m-1][n-1])printf("God please help our poor hero.\n");
		else
		{
			printf("It takes %d seconds to reach the target position, let me show you the way.\n",p.step);
			stack<node>q;
			q.push(p);
			while(p.x!=0||p.y!=0)
			{
				p=pre[p.x][p.y];
				q.push(p);
			}
				p=q.top();
				q.pop();
			while(!q.empty())
			{
				printf("%ds:(%d,%d)->(%d,%d)\n",t++,p.x,p.y,q.top().x,q.top().y);
				while(map[p.x][p.y]--)printf("%ds:FIGHT AT (%d,%d)\n",t++,p.x,p.y);
				p=q.top();
				q.pop();
			}
		}
		printf("FINISH\n");
	}
	return 0;
}
PS:说好的DP,我必须回来了。明天开始,抛除一切杂念重返DP!




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值