Labyrinth 讲解

本文解析了一款电脑游戏中的迷宫问题,玩家需在有限的左右移动次数内尽可能多地探索迷宫。通过两种宽度优先搜索算法实现,一种使用额外数组记录剩余移动次数,另一种利用双端队列区分不同方向的移动。

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

洛谷官方题目

题目描述

你正在玩一款电脑游戏。在其中一关,你位于一个 n 行 m 列的迷宫。每个格子要么是可以通过的空地,要么是障碍。迷宫的起点位于第 r 行第 c 列。你每一步可以向上、下、左、右中的一个方向移动一格,前提是那一格不是障碍。你无法越出迷宫的边界。 不幸的是,你的键盘快坏了,所以你只能向左移动不超过 x 格,并且向右移动不超过 y 格。因为上下键情况良好,所以对向上和向下的移动次数没有限制。 现在你想知道在满足上述条件的情况下,从起点出发,有多少格子可以到达(包括起点)?

输入描述

第一行包含两个数 n,m (1 <= n, m, <= 2000),表示迷宫的行数和列数。 第二行包含两个数 r,c (1 <= r <= n, 1 <= c <= m)表示起点位于第 r 行第 c 列。 第三行包含两个数 x,y (1 <= x,y <= 10^9),表示最多向左或向右移动的次数。 接下来 n 行描述这个迷宫,每行为一个长为 m 的由 '.' 和 '' 组成的字符串。 '.' 表示空地, '' 表示障碍。 输入保证起点不是障碍。

输出描述

输出一个整数,表示从起点出发可以到达的格子数,包括起点本身。

样例

输入

4 5
3 2
1 2
.....
.***.
...**
*....

输出

10

这个题明显是一个宽搜(迷宫问题)的题目,我们需要定义方向数组,以及两个额外的数组,在bfs中的for循环中,需要特判i==2||i==3时的情况,下面是参考代码

#include<bits/stdc++.h>
using namespace std;
int n,m,r,c,x,y;
int dx[5]={-1,1,0,0};//方向数组
int dy[5]={0,0,-1,1};
char a[2005][2005];
int vis[2005][2005],cnt=0;
int aa[2005][2005],ab[2005][2005];//额外变量,用于存储左和右的步数的
int qx[4000005]={0},qy[4000005]={0};
void bfs(){//bfs
	int front=0,rear=0;
	qx[rear]=r;
	qy[rear++]=c;
	aa[r][c]=x;
	ab[r][c]=y;
	vis[r][c]=1;
	while(front<rear){
		int x2=qx[front];
		int y2=qy[front++];
		for(int i=0;i<=3;i++){
			int xx=x2+dx[i];
			int yy=y2+dy[i];
			aa[xx][yy]=aa[x2][y2];
			ab[xx][yy]=ab[x2][y2];
			if(i==2){//特判
				aa[xx][yy]--;
			}
			else if(i==3){
				ab[xx][yy]--;
			}
			if(xx>0&&xx<=n&&yy>0&&yy<=m&&a[xx][yy]!='*'&&vis[xx][yy]==0&&aa[xx][yy]>=0&&ab[xx][yy]>=0){
				qx[rear]=xx;
				qy[rear++]=yy;
				vis[xx][yy]=1;
				cnt++;
			}
		}
	}
}
int main(){
	cin>>n>>m;
	cin>>r>>c;
	cin>>x>>y;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
		}
	}
	bfs();
	cout<<cnt+1<<endl;//因为要加起点,所以+1
	return 0;
}

当然了,这个题也可以使用双端队列来实现

首先要明确移动方向,上下移动没有限制,向左不超过x次,向右不超过y次,所以要判断向左和向右是否合理,可以保存到达每个点,这个点还可以用多少个向左和向右键,那就需要一个双端队列了

struct node{
	int x;//行 
	int y;//列 
	int l;//左有多少次 
	int r;//右有多少次 
}dq[N*N*2];//双端队列 

根据上下移动方向入队,如果向左或向右就队尾入队,向上向下移动就在对头入队,使用一个 switch

#include<bits/stdc++.h>
#include<iostream>
using namespace std;
const int N=2010;
struct node{
	int x;
	int y;
	int l;
	int r;
}dq[N*N*2];
char g[N][N];//地图
bool vis[N][N];//标记访问数组
int head,tail,r,c,x,y,n,m,ans;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,1,-1};//方向数组
void bfs(){
	head=N*N;
	tail=N*N;
	tail++;
	dq[tail].x=r-1;
	dq[tail].y=c-1;
	dq[tail].l=x;
	dq[tail].r=y;
	vis[r-1][c-1]=1;//将第一个点入队
	while(head!=tail){
		head ++;
		node t1=dq[head];
		for(int i=0;i<4;i++){
			node t2=t1;
			t2.x+=dx[i];
			t2.y+=dy[i];
			if(t2.x<0||t2.x>=n||t2.y<0||t2.y>=m||g[t2.x][t2.y]=='*'||vis[t2.x][t2.y]){
				continue;
			}
			switch(dy[i]){
				case 0://上下移动,对头入列
				ans++;
				dq[head]=t2;
				head--;
				vis[t2.x][t2.y]=1;
				break;
				case 1://向右移动,对尾入列
				if(!t2.r)break;
				ans++;
				tail++;
				dq[tail]=t2;
				dq[tail].r--;
				vis[t2.x][t2.y]=1;
				break;
				case -1://向左移动,对位入列
				if(!t2.l)break;
				ans++;
				tail++;
				dq[tail]=t2;
				dq[tail].l--;
				vis[t2.x][t2.y]=1;
				break;
			}
		}
	}
}
int main(){
	ans=1;
	cin>>n>>m>>r>>c>>x>>y; 
	for(int i=0;i<n;i++){
		cin>>g[i];
	}
	bfs();
	cout<<ans;
	return 0;
}

前行的路,不怕万人阻挡,只怕自己投降。人生的帆,不怕狂风巨浪,只怕自己没胆量。相信自己,定能铸造人生辉煌!

希望大家多多支持,一键三连哦                See you next time

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值