FZU 2124 吃豆人 BFS

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

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

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

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

Input

输入包含多组数据。输入第一行有两个个整数n,m(2<=n,m<=20),接着一个n*m的地图矩阵。

对于50%的数据,地图上没有道具。

Output

输出一行,最快用多少s吃到豆子,结果保留1位小数,如果吃不到,输出-1。

Sample Input

2 2
XP
B.
3 2
XP
.S
B.

Sample Output

1.2
1.7


这道题每个点中2种状态,可以被加速走过,可以无加速走过,开一个vis[N][N][2],然后跑bfs就行了

有一个点需要提的就是因为吐舌头的时间无论怎样都小于走路的时间,所以走到与终点一条直线的时候,直接吐舌头就行了。

我bfs姿势还是不够熟练啊,还是火山哥666.



#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>

using namespace std;
const int N = 30;

struct node{
    int x,y;
    int acc;     ///是否加速
    double time; ///时间
};
int n,m;
char s[N][N];
double vis[N][N][2];   ///每个点有2种状态,加速走过最短时间和没加速走过最短时间
int dir[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};

bool check(int x,int y)
{
    if(x < 1 || x > n || y < 1 || y > m)
        return false;
    return true;
}

void bfs(int sx,int sy,int ex,int ey)
{
    for(int i = 0;i < N;i++) for(int j = 0;j < N;j++) vis[i][j][0] = vis[i][j][1] = 10000.0; ///初始化
    node t = {sx,sy,0,0};
    queue<node> q;
    q.push(t);
    vis[sx][sy][0] = 0;
    while(!q.empty()){
        node u = q.front();
        q.pop();
        if(u.x == ex || u.y == ey){     ///走到终点的那条直线上
            int minx = min(u.x,ex),maxx = max(u.x,ex);
            int miny = min(u.y,ey),maxy = max(u.y,ey);
            bool flag = true;
            for(int i = minx;i <= maxx;i++)
                for(int j = miny;j <= maxy;j++)
                    if(s[i][j] == 'X') flag = false;
            if(flag){
                vis[ex][ey][u.acc] = min(vis[ex][ey][u.acc],u.time+0.2*(maxx-minx+maxy-miny));
            }
        }
        for(int i = 0;i < 4;i++){       ///四个方向走
            int tx = u.x+dir[i][0],ty = u.y+dir[i][1];
            if(!check(tx,ty) || s[tx][ty] == 'X') continue;
            node newnode = {tx,ty,u.acc,u.time};
            if(u.acc) newnode.time += 0.5;
            else      newnode.time += 1.0;
            if(s[tx][ty] == 'S')
                newnode.acc = 1;
            if(vis[tx][ty][newnode.acc] > newnode.time){
                vis[tx][ty][newnode.acc] = newnode.time;
                q.push(newnode);
            }
        }
    }
    double ans = min(vis[ex][ey][0],vis[ex][ey][1]);
    if(ans == 10000.0) puts("-1");
    else printf("%.1f\n",ans);
}

int main()
{
    while(scanf("%d%d",&n,&m) != EOF){
        int sx,sy;  ///起点
        int bx,by;  ///终点
        for(int i = 1;i <= n;i++){
            scanf("%s",s[i]+1);
            for(int j = 1;j <= m;j++)
                if(s[i][j] == 'P') sx = i,sy = j;
                else if(s[i][j] == 'B') bx = i,by = j;
        }
        bfs(sx,sy,bx,by);
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值