[蓝桥杯 2018 国 C] 迷宫与陷阱

题目链接:迷宫与陷阱

这道题目跟我们平时做的bfs不同的是 多了一个"无敌状态" 那么也就需要我们去比较有无敌状态经过陷阱和不走陷阱的最少的步数。

先说说我之前的思路吧:

开一个vis[N][N]表示走到(x,y) 这个点所需最小的步数,

再开一个st[N][N]表示这个无敌状态还能持续多少步,假设%这个点为0,一步步增多,超过k结束

这个思路是正确的,但。。。。

没错,内存超限了。。。

想看原代码的话如下:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N =1005;
char a[N][N];
int vis[N][N];
int st[N][N];
int n,k,sx,sy,ex,ey;
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
struct node{
	int x,y;
};

void bfs(int sx,int sy){
	queue<node>q;
	q.push({sx,sy});
	while(!q.empty()){
		int x=q.front().x;
		int y=q.front().y;
		q.pop();
		for(int i=0;i<4;i++){
			int nx=x+dx[i];
			int ny=y+dy[i];
			if(nx<1||nx>n||ny<1||ny>n)continue;
			if(a[nx][ny]=='#')continue;
			if(vis[nx][ny]<0x3f/2&&st[nx][ny]<st[x][y])continue;
			if(st[x][y]>k-1&&a[nx][ny]=='X')continue;
			st[nx][ny]=min(st[nx][ny],st[x][y]+1);
			vis[nx][ny]=vis[x][y]+1;
			q.push({nx,ny});
		}
	}
}

int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n>>k;
	sx=sy=1;
	ex=ey=n;
	memset(vis,0x3f,sizeof(vis));
	memset(st,0x3f,sizeof(st));
	vis[sx][sy]=0;
	for(int i=1;i<=n;i++){
		string s;cin>>s;
		for(int j=1;j<=n;j++){
			a[i][j]=s[j-1];
			if(a[i][j]=='%'){
				st[i][j]=0;
			}
		}
	}

	if(a[sx][sy]=='.')bfs(sx,sy);

//	for(int i=1;i<=n;i++){
//		for(int j=1;j<=n;j++){
//			cout<<vis[i][j]<<" ";
//		}
//		cout<<"\n";
//	}

	if(vis[ex][ey]==0x3f)cout<<-1<<"\n";
	else cout<<vis[ex][ey]<<"\n";

	return 0;
}

那么怎么考虑将这个无敌状态伴随着呢?那么我们可以考虑将这个状态放到struct结构体里面,因为queue中提取的x,y就是我要遍历的这个点,所以当前的状态就正好可以表示,那么同样我也可以将步数塞进去,那么此时就少了st数组,那么vis数组的作用在于记录当前这个点的无敌状态。

为什么还要用vis记录无敌状态呢?

这就考虑到跟上一个点比较了,原本的图遍历我们只需走一次即可,那么出现了新的无敌状态就要考虑我是不是可以先去拿这个无敌状态然后往回走再去走陷阱呢?

5 3
...XX
##%#.
...#.
.###.
.....

就如例题这个,那么就要回溯,回溯的条件就是当前的无敌值一定是比我要去的无敌值大。

因为不可能走比自己无敌值小的点(遍历过的点)

代码附上:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N =1005;
char a[N][N];
int vis[N][N];//走到该点的无敌步数多少
int n,k,sx,sy,ex,ey;
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
struct node{
	int x,y,w,st;
};
bool flag=false;

void bfs(int sx,int sy){
	queue<node>q;
	q.push({sx,sy,0,0});
	vis[sx][sy]=0;
	while(!q.empty()){
		node t=q.front();
		q.pop();
		if(t.x==ex&&t.y==ey){
			flag=true;
			cout<<t.st<<"\n";
			return;
		}
		for(int i=0;i<4;i++){
			int nx=t.x+dx[i];
			int ny=t.y+dy[i];
			if(nx<1||nx>n||ny<1||ny>n)continue;
			if(a[nx][ny]=='#')continue;
			if(t.w==0&&a[nx][ny]=='X')continue;
			int w=max(0,t.w-1);//计算目前的无敌值
			if(a[nx][ny]=='%'){
				w=k;
			}//2 1 0
			if(vis[nx][ny]>=w)continue;//回溯的条件
			vis[nx][ny]=w;
			q.push({nx,ny,w,t.st+1});
		}
	}
}

int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n>>k;
	sx=sy=1;
	ex=ey=n;
	memset(vis,-1,sizeof(vis));
	vis[sx][sy]=0;
	for(int i=1;i<=n;i++){
		string s;cin>>s;
		for(int j=1;j<=n;j++){
			a[i][j]=s[j-1];
		}
	}

	if(a[sx][sy]=='.')bfs(sx,sy);

//	for(int i=1;i<=n;i++){
//		for(int j=1;j<=n;j++){
//			cout<<vis[i][j]<<" ";
//		}
//		cout<<"\n";
//	}

	if(!flag)cout<<-1<<"\n";

	return 0;
}
相关推荐
幼儿园园霸柒柒31 分钟前
第七章: 7.3求一个3*3的整型矩阵对角线元素之和
c语言·c++·算法·矩阵·c#·1024程序员节
忘梓.1 小时前
排序的秘密(1)——排序简介以及插入排序
数据结构·c++·算法·排序算法
福大大架构师每日一题1 小时前
文心一言 VS 讯飞星火 VS chatgpt (384)-- 算法导论24.5 4题
算法·文心一言
云卓科技1 小时前
无人车之路径规划篇
人工智能·嵌入式硬件·算法·自动驾驶
摆烂小白敲代码2 小时前
背包九讲——背包问题求方案数
c语言·c++·算法·背包问题·背包问题求方案数
头真的要秃啦2 小时前
Linux 无名管道
linux·运维·算法
极智视界2 小时前
无人机场景数据集大全「包含数据标注+划分脚本+训练脚本」 (持续原地更新)
算法·yolo·目标检测·数据集标注·分割算法·算法训练·无人机场景数据集
passer__jw7672 小时前
【LeetCode】【算法】208. 实现 Trie (前缀树)
算法·leetcode
shenweihong2 小时前
javascript实现md5算法(支持微信小程序),可分多次计算
javascript·算法·微信小程序
stm 学习ing2 小时前
C语言 循环高级
c语言·开发语言·单片机·嵌入式硬件·算法·嵌入式实时数据库