AOJ 866 飞越原野 【BFS】

题面:

在一片广阔的土地上,有一个鸟人,他需要从这里穿过原野,回到基地。这片原野上,有平地(P)、有湖泊(L),因为鸟人可以飞,所以呢,有的时候,他可以飞越湖泊。现在,鸟人需要用最快的时间,回到基地。
假设原野是一个m*n的矩阵,有两种地形,用P和L表示。鸟人只能停留在平地上。他目前处在(1,1)这个位置,而目的地是(m,n)。他可以向上下左右四个方向移动,或者飞行。每移动一格需要1个单位时间。而飞行无论飞多远,都只需要1个单位时间。飞行的途中不可以变方向,也就是说飞行也只能是上下左右四个方向。并且一次飞行最终必须降落在平地上。当然,受到能量的限制,鸟人不能无限制的飞行,他总共最多可以飞行的距离为D。
Input
第一行是三个整数,m,n,D,三个数都不超过100,下面是一个m*n的矩阵,表示原野
Output
一个整数,为最短时间,如果无法到达,则输出“impossible”
Sample Input
4 4 2
PLLP
PPLP
PPPP
PLLP
Sample Output
5

大致思路:

通过一个节点,记录当前的x,y坐标,所用时间,剩余的可飞行距离。
开一个三维的visit数组记录走过的路径,因为需要额外的维度来记录剩余的飞行能力。因为,同样是到达一个点,不同的飞行剩余距离,所得答案有可能不同。
利用BFS进行搜索。不同的是,一般的BFS只需要枚举4个方向走一步的情况,而这个题则需要多枚举飞行的情况。也就是说,枚举每一种可能,走路,飞行2格、3格···一直到最大剩余飞行距离。对于每一个节点都这么操作。就可以得到答案。
P.S. 手写队列比用STL快,但需要将队列开大一点。(10w不够,应该是状态数大于10w。我开50w过了)。

代码:

#include<iostream>
#include<cstring>
using namespace std;
char mp[110][110];
int n,m,d;
bool visit[110][110][110];
typedef struct{
    int x,y,d,time;
}Node;
const int maxn=500000;
typedef struct{
    Node a[maxn];
    int head,tail;
}Que;
bool check(int x,int y,int d)//判断能不能到这里去
{
    if(x<1||x>m||y<1||y>n)
        return false;
    if(visit[x][y][d]||mp[x][y]=='L')
        return false;
    return true;
}
Que q;
int main()
{
    ios::sync_with_stdio(false);
    memset(visit,false,sizeof(visit));
    int dis1[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
    int ans=0;
    bool succ=false;
    cin>>m>>n>>d;
    for(int i=1;i<=m;++i)
        for(int j=1;j<=n;++j)
            cin>>mp[i][j];
    Node a;
    a.y=a.x=1;
    a.d=d;
    a.time=0;
    q.head=0;
    q.tail=0;
    q.a[q.tail++]=a;
    mp[1][1]='L';
    while(q.tail!=q.head)
    {
        Node b=q.a[q.head++];
        q.head%=maxn;
        if(b.x==m&&b.y==n){
            ans=b.time;
            succ=true;
            break;
        }
        int dx,dy,dd;
        for(int i=0;i<4;++i){//枚举走路的所有情况
            dx=b.x+dis1[i][0];
            dy=b.y+dis1[i][1];
            dd=b.d;
            if(check(dx,dy,dd)){
                Node c;
                c.x=dx;c.y=dy;c.d=dd;c.time=b.time+1;
                q.a[q.tail++]=c;
                q.tail%=maxn;
                visit[dx][dy][dd]=true;
            }
        }
        for(int i=0;i<4;++i){
            for(int j=2;j<=b.d;++j){//枚举飞行的所有情况
                dx=b.x+dis1[i][0]*j;
                dy=b.y+dis1[i][1]*j;
                dd=b.d-j;
                if(check(dx,dy,dd)){
                    Node c;
                    c.x=dx;c.y=dy;c.d=dd;c.time=b.time+1;
                    q.a[q.tail++]=c;
                    q.tail%=maxn;
                    visit[dx][dy][dd]=true;
                }
            }
        }
    }
    if(succ)
        cout<<ans<<endl;
    else
        cout<<"impossible"<<endl;
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值