FZU 2124 吃豆人(BFS 坑有点多)

题目链接:【FZU 2124】

题目描述:

吃豆人是一款非常经典的游戏,游戏中玩家控制吃豆人在地图上吃光所有豆子,并且避免被怪物抓住。

这道题没有怪物,将游戏的画面分成n*m的格子,每格地形可能为空地或者障碍物,吃豆人可以在空地上移动,吃豆人每移动一格需要1s时间,并且只能朝上下左右四个方向移动,特别的是吃豆人还能吐出舌头,舌头每移动一格需要0.1s时间,舌头只可以走直线。不必考虑吃豆人转身所需要的时间。

举例,吃豆人在(1,1)坐标,而豆子在(1,5)坐标,并且中间没有障碍物,此时朝豆子方向吐舌头~,经过0.8s就可以吃到豆子(来回各0.4s,吐出去的舌头要缩回来的嘛)。

游戏中还有加速道具,一旦得到加速道具,吃豆人就获得2倍移动速度,吐舌头的速度没有增加,即走1格用0.5s。现在地图上有且只有一颗豆子。游戏中有.代表空地;X表示障碍,吃豆人不能越过障碍;B代表豆子;S代表加速道具,并且地图上道具总数不超过1个,道具所在的位置为空地,得到道具后立即使用,道具立即消失,地形变为空地,不能用舌头去取道具;P表示吃豆人,吐舌头的时候吃豆人不能移动。

注意点:

1、用舌头卷豆子时这条路不能出现‘X’

2、得到加速器前走过的地方,得到加速器之后仍然可以走,因此我们应该用三维数组来标记走过的地方

3、输出保留一位小数,不存在的就输出-1

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
using namespace std;
char str[30][30];
int vis[30][30][2];
int f[4][2] = {0,1,1,0,0,-1,-1,0};
int x1,y1, x2,y2, n, m;
struct node
{
	int x, y;
	double time, l;
}s, e;
bool isok(int xs, int ys, int xe, int ye)
{
	if(xs==xe)
	{
		for(int i=min(ys, ye); i<max(ys, ye); i++)
		{
			if(str[xs][i]=='X') return false; 
		}
	}
	if(ys==ye)
	{
		for(int i=min(xs,xe); i<max(xs,xe); i++)
		{
			if(str[i][ys]=='X') return false;
		}
	}
	return true;
}
double bfs()
{
	memset(vis, 0, sizeof(vis));
	queue<node>q;
	s.x=x1, s.y=y1, s.time=0, s.l=1;
	q.push(s), vis[x1][y1][0]=1;
	double ans=1e9;
	while(!q.empty())
	{
		s = q.front(), q.pop();
		if(s.x==x2 && isok(s.x,s.y,x2,y2)) 
		{
			if(s.y<y2) ans = min(ans, s.time+0.2*(y2-s.y));
			else ans = min(ans, s.time+0.2*(s.y-y2));
			continue;
		}
		if(s.y==y2 && isok(s.x,s.y,x2,y2))
		{
			if(s.x<x2) ans = min(ans, s.time+0.2*(x2-s.x));
			else ans = min(ans, s.time+0.2*(s.x-x2));
			continue;
		}
		for(int i=0; i<4; i++)
		{
			e = s;
			e.x+=f[i][0], e.y+=f[i][1], e.time += e.l;
			if(e.x<0||e.x>=n||e.y<0||e.y>=m) continue;
			if(str[e.x][e.y]=='X') continue;
			if(e.l==1&&vis[e.x][e.y][0]) continue;
			if(e.l==0.5&&vis[e.x][e.y][1]) continue; 
			if(str[e.x][e.y]=='S') e.l=0.5;
			if(e.l==1) vis[e.x][e.y][0] = 1;
			else vis[e.x][e.y][1]=1;
			q.push(e);
		}
	}
	return ans==1e9 ? -1:ans;
}
int main()
{
	while(~scanf("%d%d", &n, &m))
	{
		for(int i=0; i<n; i++)
		{
			scanf("%s", str[i]);
			for(int j=0; j<m; j++)
			{
				if(str[i][j]=='P') x1=i,y1=j;
				if(str[i][j]=='B') x2=i,y2=j;
			}
		}
		double ans=bfs();
		if(ans<0) printf("-1\n");
		else printf("%.1lf\n", ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值