2018.10.03 迷宫游戏(状压+bfs)

版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/82934806

描述

Pluto 已经很久没有玩游戏了,今天 Pluto 难得能够歇一天。于是,Pluto 决定要玩一个非常好玩的迷宫游戏。这个迷宫游戏在一个 n 行 m 列的矩阵上进行,游戏中的任意时刻不能走出这个矩阵。在这个矩阵中,有下列几种元素:
. :表示一块平地。
X :表示一堵墙,不能经过。
S :表示游戏的起点,有且仅有一个。
T :表示游戏的终点,有且仅有一个。
A~H :表示一种类型的门,每种类型的门最多只会出现一次。
a~h :表示每种类型的门对应的钥匙,每种类型的钥匙最多只会出现一次,并且保证只会与对应类型的门同时出现。
在这个游戏中,玩家从起点开始,每次向上下左右中的一个方向移动一格,若发生下列任意一种或多种情形,则该步移动不合法,游戏退出。
1 . 走出矩阵。
2 . 移动后的格子中是墙。
3 . 移动后的格子中是门,且还未获得对应的钥匙。
若玩家走到一个有钥匙的格子中,则玩家将获得格子中的钥匙(注意:玩家不能选择放弃获取。)最终,若玩家到达终点,则游戏完成。
现在,Pluto 希望你能帮助他在完成游戏的同时,获得尽量少的钥匙。如果有多解,请输出任意一解。

输入

第一行两个正整数 n,m,表示矩阵的大小。
接下来一个 n*m 的矩阵,描述这个迷宫。

输出

一共若干字符,表示你的操作序列。‘U’表示向上,‘D’表示向下,‘L’表示向 左,‘R’表示向右。(注意:输出的操作序列需保证长度不超过 10000000。

样例输入

3 4
S.a.
.X.X
ATX.

样例输出

RRLLDDR

提示

对于 50%的数据,2 ≤ n,m ≤ 100。
对于 100%的数据,2 ≤ n,m ≤ 200


状压搜索经典题。
解法:
定义当前状态: ( x , y , s t a t e ) (x,y,state) 表示当前在x行y列,钥匙的获得状态是state(二进制压缩)。
其实就是普通的bfs加上状压表示。
由于题目要求选最小的钥匙,所以这题可能会从队头和队尾两端插入节点,因此如果用STL需要用双端队列,手写双端的话空间无法承受,因此最好循环队列。
代码:

#include<bits/stdc++.h>
using namespace std;
const int lop=205*205*(1<<8)+1;
int n,m,sx,sy,tx,ty,dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
struct Node{int x,y,sta;}pre[205][205][(1<<8)+5],q[lop];
char mp[205][205],s[205],ans[lop];
bool vis[205][205][(1<<8)+5];
inline void print(int x,int y,int s){
	int mx,my,ms,cnt=0;
	while(x!=sx||y!=sy||s){
		Node tmp=pre[x][y][s];
		mx=tmp.x,my=tmp.y,ms=tmp.sta;
		if(mx<x)ans[++cnt]='D';
		else if(mx>x)ans[++cnt]='U';
		else if(my<y)ans[++cnt]='R';
		else ans[++cnt]='L';
		x=mx,y=my,s=ms;
	}
	for(int i=cnt;i;--i)putchar(ans[i]);
}
inline void bfs(){
	int hd=lop-1,tl=lop-1,pos,nx,ny,ns;
	q[hd]=(Node){sx,sy,0},vis[sx][sy][0]=1;
	while(hd<=tl){
		pos=(hd++)%lop,nx=q[pos].x,ny=q[pos].y,ns=q[pos].sta;
		if(nx==tx&&ny==ty){print(nx,ny,ns);return;}
		for(int i=0;i<4;++i){
			int ms,mx=nx+dx[i],my=ny+dy[i];
			if(!mx||!my||mx>n||my>m||mp[mx][my]=='X')continue;
			if(mp[mx][my]>='a'&&mp[mx][my]<='z'){
				int num=mp[mx][my]-'a',tmp=(ns>>num)&1;
				ms=ns^((tmp^1)<<num);
				if(vis[mx][my][ms])continue;
				vis[mx][my][ms]=true,pre[mx][my][ms]=(Node){nx,ny,ns};
				if(tmp)pos=(--hd)%lop;
				else pos=(++tl)%lop;
				q[pos]=(Node){mx,my,ms};
			}
			else if(mp[mx][my]>='A'&&mp[mx][my]<='Z'){
				int num=mp[mx][my]-'A',tmp=(ns>>num)&1;
				if(!tmp)continue;
				ms=ns;
				if(vis[mx][my][ms])continue;
				vis[mx][my][ms]=true,pre[mx][my][ms]=(Node){nx,ny,ns};
				pos=(--hd)%lop,q[pos]=(Node){mx,my,ms};
			}
			else{
				ms=ns;
				if(vis[mx][my][ms])continue;
				vis[mx][my][ms]=true,pre[mx][my][ms]=(Node){nx,ny,ns};
				pos=(--hd)%lop,q[pos]=(Node){mx,my,ms};
			}
		}
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i){
		scanf("%s",s+1);
		for(int j=1;j<=m;++j){
			if(s[j]=='S')sx=i,sy=j,mp[i][j]='.';
			else if(s[j]=='T')tx=i,ty=j,mp[i][j]='.';
			else mp[i][j]=s[j];
		}
	}
	bfs();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/82934806
今日推荐