NCSTOJ:获取所有钥匙的最短路径

E : 获取所有钥匙的最短路径
Time Limit:2 Sec Memory Limit:128 MiB
Back Submit Edit

Description
给定一个二维网格 grid。

“.” 代表一个空房间, “#” 代表一堵墙, “@” 是起点,(“a”, “b”, …)代表钥匙,(“A”, “B”, …)代表锁。

我们从起点开始出发,一次移动是指向四个基本方向之一行走一个单位空间。我们不能在网格外面行走,也无法穿过一堵墙。

如果途经一个钥匙,我们就把它捡起来。除非我们手里有对应的钥匙,否则无法通过锁。

假设 K 为钥匙/锁的个数,且满足 1 <= K <= 6,字母表中的前 K 个字母在网格中都有自己对应的一个小写和一个大写字母。

换言之,每个锁有唯一对应的钥匙,每个钥匙也有唯一对应的锁。

另外,代表钥匙和锁的字母互为大小写并按字母顺序排列。

输出获取所有钥匙所需要的移动的最少次数。如果无法获取所有钥匙,返回 -1 。

Input
整数n, m,代表grid的行、列 (1 ≤ n,m ≤ 30)

以下为n*m的矩阵

Output
获取所有钥匙所需要的移动的最少次数
Sample Input
3 5
@.a.#
###.#
b.A.B
Sample Output
8
More Info
输入:

3 5

@…aA

…B#.

…b

输出:

6

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
char  grid[35][35];//用于存储地图
bool vis[35][35][65];//用true判断该位置持有的钥匙组合状态
struct State{
	int keys,x,y,step;
	State(int keys,int x,int y,int step):keys(keys),x(x),y(y),step(step){
	}	
}; 
int sx=-1,sy=-1;//用于记录初始位置 
int toState=0;//用状态压缩存储拿到所有钥匙的状态 
int Next[4][2]={0, 1, 0, -1, 1, 0, -1, 0};
int n,m;
int bfs(){
	queue<State>Q;//用队列来模拟bfs搜索
	Q.push(State(0,sx,sy,0));//初始状态入队
	vis[sx][sy][0]=1;//记录初始状态 
	while(!Q.empty())
	{
		State head=Q.front();
		Q.pop();//用head记录当前位置数据在出队
	
		for(int k=0;k<4;k++)//通过该层循环实现上下左右移动 
		{
			int x=head.x,y=head.y,step=head.step,keys=head.keys;
		int nx=x+Next[k][0];
		 int ny=y+Next[k][1];
		 if(nx>=0&&ny>=0&&nx<n&&ny<m&&grid[nx][ny]!='#')  //判断当移动后的位置在地图中并且不是墙的时候 
		 {
	       if(islower(grid[nx][ny]))
		   keys|=1<<(grid[nx][ny]-'a');//通过状态压缩更新拿到的钥匙数
		    
		   else if(isupper(grid[nx][ny])&&!(keys>>(grid[nx][ny]-'A')&1))
		   continue;//判断当前门有没有对应的钥匙若没有进行下一个方向的判断
		   if(!vis[nx][ny][keys])  //当,当前位置所拿钥匙的组合数没有出现过时进行数据更新 
		   {
		   	
		   	if(keys==toState)return step+1;//当往前走一步时能完成操作时,步数加一向前走一步 
		   	vis[nx][ny][keys]=true;
		   	Q.push(State(keys,nx,ny,step+1));//当该位置还没走过时入队模拟bfs搜索
			   //因为这是队列所以可能会有多个可能的结果,但最小的步数一定被先搜索到
			    
		   	
		   	
		   	
					}	 	
		 	
		 	
		 }
			
		}
		
	
		
		 
	}
	 
		return -1;
	
	
	
}
int main(){
//	freopen("qwe.txt","r",stdin);
	
	cin>>n>>m;
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)
		{
			cin>>grid[i][j];
			if(grid[i][j]=='@')
			sx=i,sy=j;
			if(grid[i][j]>='a'&&grid[i][j]<='f')
			toState|=1<<(grid[i][j]-'a');//通过状态压缩更新持有钥匙的状态 
			
			
		}
	}
	cout<<bfs()<<endl;
	return 0;
	
	
	
}

猜你喜欢

转载自blog.csdn.net/qq_42635159/article/details/89323705