洛谷官方题目
题目描述
你正在玩一款电脑游戏。在其中一关,你位于一个 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