飞跃原野(BFS,“飞行”限制,标记增维)

在一片由平地和湖泊构成的原野上,一名鸟人需要从起点(1,1)出发,利用步行和有限次数的飞行能力,尽快抵达终点(m,n)。此问题可通过广度优先搜索算法求解,考虑不同地形对移动的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

友情链接

飞越原野

Description
在一片广阔的土地上,有一个鸟人,他需要从这里穿过原野,回到基地。这片原野上,有平地(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


思路

有两种移动方式
步行:上下左右移动一格,只能通过平原,“能量”不变。
飞行:上下左右移动任意格,可以穿越湖泊和平原,但是起点和终点必须是平原,“能量”减少飞行的长度。

两种移动方式要分开写,步行就是通常bfs的那种拓展节点的方式,飞行需要在方向上加上一个循环变量j(飞行距离)。

注意总共最多可以飞行的距离(能量)为D,不是每次可以飞的距离。


代码示例

#include<iostream>
#include<queue>
#define MAX 101
using namespace std;
    
char map[MAX][MAX];
int vis[MAX][MAX][MAX];
int dir[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
    
int m,n,flag,val,d;
    
struct point{//将坐标看做结构体在队列中操作 
    int x,y,fei,num;
    point(int xx,int yy,int dd,int nn){
        x=xx;
        y=yy;
        fei=dd;
        num=nn;
    }
};
queue<point> q;//声明结构体点队列
    
bool visit(int x,int y,int fei){//判断是否能visit
    if(x>=0&&x<m&&y>=0&&y<n&&map[x][y]=='P'&&vis[x][y][fei]==0){
        return true;
    }
    else return false;
}
 

void bfs(){
    q.push(point(0,0,d,0));//将起始点放入队列
    vis[0][0][d]=1;
    while(!q.empty())//只要队列不空 
    {
        point p=q.front();
        q.pop();
        if(p.x==m-1&&p.y==n-1){
            flag=1;//找到 
            val=p.num;
            break;
        }
                
        for(int i=0;i<4;++i){//走 (只能走P)
            if(visit(p.x+dir[i][0],p.y+dir[i][1],p.fei)){
                q.push(point(p.x+dir[i][0],p.y+dir[i][1],p.fei,p.num+1));
                vis[p.x+dir[i][0]][p.y+dir[i][1]][p.fei]=1;
            }
        }
                
        for(int i=0;i<4;++i){//飞 (有fei的限制) 
            for(int j=2;j<=p.fei;++j){
                if(visit(p.x+dir[i][0]*j,p.y+dir[i][1]*j,p.fei-j)){
                    q.push(point(p.x+dir[i][0]*j,p.y+dir[i][1]*j,p.fei-j,p.num+1));
                    vis[p.x+dir[i][0]*j][p.y+dir[i][1]*j][p.fei-j]=1;
                }
            }
    	}
    } 
}

 
int main()
{
    std::ios::sync_with_stdio(false);
    cin>>m>>n>>d;
    for(int i=0;i<m;++i){
        cin>>map[i];
    }
    bfs();
    if(flag==1) cout<<val<<endl;
    else cout<<"impossible"<<endl;
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值