[蓝桥杯 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;
}
相关推荐
Lenyiin16 分钟前
01.02、判定是否互为字符重排
算法·leetcode
鸽鸽程序猿32 分钟前
【算法】【优选算法】宽搜(BFS)中队列的使用
算法·宽度优先·队列
Jackey_Song_Odd32 分钟前
C语言 单向链表反转问题
c语言·数据结构·算法·链表
Watermelo61736 分钟前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript
乐之者v41 分钟前
leetCode43.字符串相乘
java·数据结构·算法
A懿轩A2 小时前
C/C++ 数据结构与算法【数组】 数组详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·数组
古希腊掌管学习的神2 小时前
[搜广推]王树森推荐系统——矩阵补充&最近邻查找
python·算法·机器学习·矩阵
云边有个稻草人2 小时前
【优选算法】—复写零(双指针算法)
笔记·算法·双指针算法
半盏茶香2 小时前
在21世纪的我用C语言探寻世界本质 ——编译和链接(编译环境和运行环境)
c语言·开发语言·c++·算法
忘梓.3 小时前
解锁动态规划的奥秘:从零到精通的创新思维解析(3)
算法·动态规划