首页 > 其他分享 >走迷宫(可使用激光)

走迷宫(可使用激光)

时间:2024-11-16 15:46:31浏览次数:1  
标签:ch int 激光 迷宫 maz3 nx ny 使用 1010

题目描述:
给定一个 n×m 的迷宫,迷宫由 "#" 与"." 两种字符组成。其中 "#" 代表障碍物,"." 表示空地。迷宫中还有一个起点 "S" 和一个终点 "E" ,它们都可以视为空地。
由于近期迷宫发生了塌方,导致起点和终点之间可能并不连通。幸运的是,你拥有一种超能力——在迷宫中移动时(移动方向为上、下、左、右四个方向之一),可以在当前位置朝任一方向(上、下、左、右四个方向之一)释放激光。激光能够清除该方向上所有的障碍物,并且这种超能力至多只能使用一次。
现在,你需要判断是否能利用这种超能力成功从起点到达终点。

输入描述:
第一行给定两个正整数n,m,(2<=n,m<=1000),分别表示迷宫的行数和列数。
下面 n 行,每行 m 个字符,描述迷宫的具体布局。字符只包含 "#"、"."、"S" 和 "E",并且起点与终点有且仅有一个。

输出描述:
能够到达终点输出 YES ;否则输出 NO

思路1:使用DFS暴力搜索,在搜索的过程中一但遇到障碍物就使用激光,然后接着搜索.

#include<bits/stdc++.h>
using namespace std;
int m,n;
char maz3[1010][1010];//这个是迷宫
bool visited[1010][1010];//判断走过的地方防止无限递归
int sx,sy,ex,ey;//起始点和终止点

//使用激光清除障碍物,为了方便撤回操作,使用感叹号代替障碍物
void usetrick(int x,int y,int dir){
	while(0 <= x and 0 <= y and x < m and y < n){
		if(maz3[x][y] == '#')  maz3[x][y] = '!';
		if(dir == 0) x--;
		if(dir == 1) y++;
		if(dir == 2) x++;
		if(dir == 3) y--;
	}
}

void unusetrick(int x,int y,int dir){
	while(0 <= x and 0 <= y and x < m and y < n){
		if(maz3[x][y] == '!')  maz3[x][y] = '#';
		if(dir == 0) x--;
		if(dir == 1) y++;
		if(dir == 2) x++;
		if(dir == 3) y--;
	}
}	

//DFS递归搜索
bool ch3ck(bool trick,int x,int y){
	if(x == ex and y == ey) return true;
	bool flag = false;//能不能走到E点
	
	for(int i=0;i<4;++i){//四个方向
		int nx = x,ny = y;//现在的坐标
		
		if(i == 0) nx--;
		if(i == 1) ny++;
		if(i == 2) nx++;
		if(i == 3) ny--;
		
		if(0 <= nx and 0 <= ny and nx < m and ny < n and !visited[nx][ny]){//没走过并且在迷宫内
			visited[nx][ny] = true;
			if(maz3[nx][ny] != '#'){//不是障碍物的话就往个下走
				if(ch3ck(trick,nx,ny)) flag = true;
			}
			else if(trick){//如果是障碍物就清除并且标记使用了trick,trick在之后的递归就不能用了
				trick = false;
				usetrick(x,y,i);
				if(ch3ck(trick,nx,ny)) flag = true;
				unusetrick(x,y,i);
				trick = true;//这两行是递归回溯
			}
			visited[nx][ny] = false;
		}
	}
	
	return flag;
}

int main(){
    
    cin >> m >> n;
    for(int i=0;i<m;++i){
        for(int j=0;j<n;++j){
        	char ch;
        	cin >> ch;
    		maz3[i][j] = ch;
        	if(ch == 'S'){
        		sx = i;
        		sy = j;
        	}
        	if(ch == 'E'){
        		ex = i;
        		ey = j;
        	}
        }
    }
    
    bool trick = true;
    if(ch3ck(trick,sx,sy)){
    	cout << "YES";
    }
    else{
    	cout << "NO";
    }
    
    
    return 0;
}

由于该算法的复杂度为O(n*n*m*m),显然超时了(10^12)


思路2:使用队列BFS代替递归DFS

#include<bits/stdc++.h>
using namespace std;
int m,n;
char maz3[1010][1010];
bool visited[1010][1010];
int sx,sy,ex,ey;

void usetrick(int x,int y,int dir){
	while(0 <= x and 0 <= y and x < m and y < n){
		if(maz3[x][y] == '#')  maz3[x][y] = '!';
		if(dir == 0) x--;
		if(dir == 1) y++;
		if(dir == 2) x++;
		if(dir == 3) y--;
	}
}

void unusetrick(int x,int y,int dir){
	while(0 <= x and 0 <= y and x < m and y < n){
		if(maz3[x][y] == '!')  maz3[x][y] = '#';
		if(dir == 0) x--;
		if(dir == 1) y++;
		if(dir == 2) x++;
		if(dir == 3) y--;
	}
}	

bool check(int x,int y){
	int dx[] = {-1,0,1,0};
	int dy[] = {0,1,0,-1};
	
	queue<pair<int,int>> q;
	q.push({x,y});
	visited[x][y] = true;
	
	while(!q.empty()){
		pair<int,int> pnow = q.front();q.pop();
		int x = pnow.first,y = pnow.second;
		
		if(x == ex and y == ey) return true;
		
		for(int i=0;i<4;++i){//四个方向
			int nx = x+dx[i],ny = y+dy[i];
			
			if(nx >= 0 and ny >= 0 and nx < m and ny < n){
				if(maz3[nx][ny] != '#' and !visited[nx][ny]){
					visited[nx][ny] = true;
					q.push({nx,ny});
				}
			}
		}
	}
	return false;
}

bool ch3ck(){
	int dx[] = {-1,0,1,0};
	int dy[] = {0,1,0,-1};
	
	queue<pair<int,int>> q;
	q.push({sx,sy});
	visited[sx][sy] = true;
	
	while(!q.empty()){
		pair<int,int> pnow = q.front();q.pop();
		int x = pnow.first,y = pnow.second;
		
		if(x == ex and y == ey) return true;
		
		for(int i=0;i<4;++i){//四个方向
			int nx = x+dx[i],ny = y+dy[i];
			
			if(nx >= 0 and ny >= 0 and nx < m and ny < n){
				if(maz3[nx][ny] != '#' and !visited[nx][ny]){
					visited[nx][ny] = true;
					q.push({nx,ny});
				}
				else{
					usetrick(nx,ny,i);
					bool visitedTmp[1010][1010];
					memcpy(visitedTmp,visited,sizeof(visited));
					if(check(nx,ny)) return true;
					memcpy(visited,visitedTmp,sizeof(visited));
					unusetrick(nx,ny,i);
				}
			}
		}
	}
	return false;
}

int main(){
    
    cin >> m >> n;
    for(int i=0;i<m;++i){
        for(int j=0;j<n;++j){
        	char ch;
        	cin >> ch;
    		maz3[i][j] = ch;
        	if(ch == 'S'){
        		sx = i;
        		sy = j;
        	}
        	if(ch == 'E'){
        		ex = i;
        		ey = j;
        	}
        }
    }
    
    if(ch3ck()){
    	cout << "YES";
    }
    else{
    	cout << "NO";
    }
    
    
    return 0;
}

在ch3ck函数中若使用激光,进入check函数搜索,虽然这两个函数都是O(m*n),但嵌套之后跟上一个代码复杂度是一样的.


思路3:从起点和重点分别做BFS搜索,找出从起点和重点能到达的地方,这一部分的复杂度是O(2*m*n) = O(m*n)
做完这一部分之后,存入两个二维数组里,方便后续工作.
例如:

很直接的能想到,如果在这个5*5迷宫里有横的一条线或者竖的一条线,这线上既有S能到的地方,又有E能到的地方,不就是能到达吗(使用激光).或者是更简单的情况不使用激光也能到达.
但是使用激光后开出来的路可能从两边走可能到达终点!!
所以解法是在比较时同时比较S能到达的一条线和E能到达的三条线

AC代码如下:

#include<bits/stdc++.h>
using namespace std;
int m,n,sx,sy,ex,ey;
int maz3[1010][1010][3];

void chSck(){
	int dx[]={-1,0,1,0};
	int dy[]={0,1,0,-1};
    queue<pair<int,int>> q;
    q.push({sx,sy});
    maz3[sx][sy][1] = 1;
    while(!q.empty()){
    	int x = q.front().first,y = q.front().second;q.pop();
    	
    	for(int i=0;i<4;++i){
    		int nx = x+dx[i],ny = y+dy[i];
    		if(nx >= 0 and ny >= 0 and nx < m and ny < n){
    			if(maz3[nx][ny][0] != '#' and !maz3[nx][ny][1]){
    				maz3[nx][ny][1] = 1;
    				q.push({nx,ny});
    			}
    		}
    	}
    }
}

void chEck(){
	int dx[]={-1,0,1,0};
	int dy[]={0,1,0,-1};
    queue<pair<int,int>> q;
    q.push({ex,ey});
    maz3[ex][ey][2] = 1;
    while(!q.empty()){
    	int x = q.front().first,y = q.front().second;q.pop();
    	
    	for(int i=0;i<4;++i){
    		int nx = x+dx[i],ny = y+dy[i];
    		if(nx >= 0 and ny >= 0 and nx < m and ny < n){
    			if(maz3[nx][ny][0] != '#' and !maz3[nx][ny][2]){
    				maz3[nx][ny][2] = 1;
    				q.push({nx,ny});
    			}
    		}
    	}
    }
}

bool ch3ck(){
	
    for(int i=0;i<m;++i){
    	int ToS = 0;
    	int ToE = 0;
    	for(int j=0;j<n;++j){
    		ToS += maz3[i][j][1];
    		ToE += maz3[i][j][2];
    		if(i>0)ToE += maz3[i-1][j][2];
    		if(i<m-1)ToE += maz3[i+1][j][2];
    	}
    	if(ToS and ToE) return true;
    }
    for(int j=0;j<n;++j){
    	int ToS = 0;
    	int ToE = 0;
    	for(int i=0;i<m;++i){
    		ToS += maz3[i][j][1];
    		ToE += maz3[i][j][2];
    		if(j>0)ToE += maz3[i][j-1][2];
    		if(j<n-1)ToE += maz3[i][j+1][2];
    	}
    	if(ToS and ToE) return true;
    }
    return false;
}

int main(){
    cin >> m >> n;
    
    for(int i=0;i<m;++i){
    	for(int j=0;j<n;++j){
    		char ch;
    		cin >> ch;
    		maz3[i][j][0] = ch;
    		if(ch == 'S'){
    			sx = i;
    			sy = j;
    		}
    		if(ch == 'E'){
    			ex = i;
    			ey = j;
    		}
    	}
    }
    chEck();
    chSck();
    
    // for(int i=0;i<m;++i){
    	// for(int j=0;j<n;++j){
    		// cout << maz3[i][j][1] << ' ';
    	// }
    	// cout << endl;
    // }
    // cout << endl;
    // for(int i=0;i<m;++i){
    	// for(int j=0;j<n;++j){
    		// cout << maz3[i][j][2] << ' ';
    	// }
    	// cout << endl;
    // }
    
    if(ch3ck()) cout << "YES";
    else cout << "NO";
    
    
    return 0;
}

标签:ch,int,激光,迷宫,maz3,nx,ny,使用,1010
From: https://www.cnblogs.com/shen-kong/p/18549394

相关文章

  • 使用while循环分别对两个vector进行赋值,该怎么做
    问题在写程序的时候遇到了这样一个问题,见代码#include<iostream>#include<vector>usingnamespacestd;boolisequal(vector<int>vshort,vector<int>vlong){ for(intindex=0;index!=vshort.size();index++) if(vshort[index]!=vlong[index]) ......
  • Enterprise Architect 的使用手册
    实验八健壮性分析一、创建空的健壮性图选中项目浏览器中的“财神银行自助银行系统”,点击Addapackage按钮为自助银行系统添加一个新的模型包。在弹出的对话框中输入名称为“3-健壮性分析”.点击确定按钮后,选中项目浏览器中的“3-健壮性分析”,点击Create Diagram按......
  • Markdown使用教程
    :smile:表情:结构......
  • 手把手教你部署并使用清华智谱ChatGLM3-6B大模型
    部署一个自己的大模型,没事的时候玩两下,这可能是很多技术同学想做但又迟迟没下手的事情,没下手的原因很可能是成本太高,近万元的RTX3090显卡,想想都肉疼,又或者官方的部署说明过于简单,安装的时候总是遇到各种奇奇怪怪的问题,难以解决。本文就来分享下我的安装部署经验,包括本地和......
  • 云原生之运维监控实践-使用Prometheus与Grafana实现对Nginx和Nacos服务的监测
    背景如果你要为应用程序构建规范或用户故事,那么务必先把应用程序每个组件的监控指标考虑进来,千万不要等到项目结束或部署之前再做这件事情。——《Prometheus监控实战》去年写了一篇在Docker环境下部署若依微服务ruoyi-cloud项目的文章,当时使用的是docker-compose在单......
  • 权限管理,chmod,chown,chgrp的使用
    修改权限-chmod通过chmod指令,可以修改文件或者目录的权限第一种方式:+、-、=变更权限u:所有者g:所有组o:其他人a:所有人(u、g、o的总和)1)chmodu=rwx,g=rx,o=x文件目录名2)chmodo+w文件目录名3)chmoda-x文件目录名(1)abc文件的所有者读写执行的权限,给所在组读执行权限,给其他......
  • docker容器镜像的制作、使用以及传递
    目录制作容器镜像使用Dockerfile制作镜像准备所需文件构建镜像怎么不使用基础镜像来构建容器镜像使用容器镜像传递容器镜像这篇文章讨论一下怎么使用docker制作容器镜像,容器镜像的使用,以及怎么传递容器镜像。制作容器镜像docker制作容器镜像推荐的方法就是使用Doc......
  • SQL Server中使用临时表进行数据备份与恢复
    在日常的数据库管理中,我们经常需要对数据进行备份和恢复操作。SQLServer提供了多种工具和命令来帮助我们完成这些任务。本文将介绍一种简单的方法,即使用临时表来备份特定记录,清空表,然后将数据恢复到表中。临时表简介在SQLServer中,临时表是一种特殊的表,它只在当前会话或当前事......
  • go fiber:使用独立的routes文件组织controller
    一,go代码:controller/articleController.gopackagecontrollerimport"github.com/gofiber/fiber/v2"typeArticleControllerstruct{}funcNewArticleController()*ArticleController{ return&ArticleController{}}func(dc*ArticleController)......
  • 未使用 `deleteLater` 而直接使用 `delete` 导致问题
    以下是一个完整的Qt代码示例,展示了未使用deleteLater而直接使用delete导致问题的情况,该示例涉及到一个简单的多线程场景,主线程创建一个工作线程,工作线程完成任务后通知主线程,在对象删除处理不当的情况下会出现崩溃等问题。示例代码#include<QObject>#include<QThread>#i......