题目要求
假设一个探险家被困在了地底的迷宫之中,要从当前位置开始找到一条通往迷宫出口的路径。迷宫可以用一个二维矩阵组成,有的部分是墙,有的部分是路。迷宫之中有的路上还有门,每扇门都在迷宫的某个地方有与之匹配的钥匙,只有先拿到钥匙才能打开门。请设计一个算法,帮助探险家找到脱困的最短路径。如前所述,迷宫是通过一个二维矩阵表示的,每个元素的值的含义如下 0-墙,1-路,2-探险家的起始位置,3-迷宫的出口,大写字母-门,小写字母-对应大写字母所代表的门的钥匙 。
输入描述
迷宫的地图,用二维矩阵表示。第一行是表示矩阵的行数和列数M和N
后面的M行是矩阵的数据,每一行对应与矩阵的一行(中间没有空格)。M和N都不超过100, 门不超过10扇。
输入例子
5 5
02111
01a0A
01003
01001
01111
输出例子
7
题目思路:
由于做这个题之前没了了解到BFS,所以赶快撸了一下课本,这里求最短距离,外加门的数量不超过10个,所以直接一个暴力BFS,又由于需要记录持有钥匙的状态,所以使用状态压缩用二进制数表示持有钥匙状态。
在BFS之前先给出初始状态设置,这里由于有一个钥匙的概念,所以问题变为如何在走的过程中记录钥匙信息,所以这里采用一个状态压缩法,用一个数来代表有没有某一把钥匙,即这个数的二进制表示时第i位为1代表有第a+i把钥匙,否则没有,相当于迷宫每一个点有1024个状态。
下面给出BFS实现代码:
int n,m,sx,sy,ex,ey;
char g[1024][1024];
int use[120][120][1400];
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
struct node
{
int x,y,k;
};
int bfs()
{
memset(use,0xff,sizeof(use));
queue<node>q;
node t;
t.x=sx;
t.y=sy;
t.k=0;
use[t.x][t.y][t.k]=0;
q.push(t);
while(!q.empty())
{
t = q.front();
q.pop();
//printf("%d %d %d %d\n",t.x,t.y,t.k,use[t.x][t.y][t.k]);
if(t.x==ex&&t.y==ey) return use[t.x][t.y][t.k];
for(int i=0;i<4;i++)//上下左右
{
node k;//分别往上下左右走
k.x = t.x + dx[i];
k.y = t.y + dy[i];
k.k = t.k;
if(k.x<0||k.x>=n||k.y<0||k.y>=m||g[k.x][k.y]=='0') continue;//直接进入下次循环
if(g[k.x][k.y]>='a'&&g[k.x][k.y]<='z')
{
k.k = k.k|(1<<(g[k.x][k.y]-'a'));//走到钥匙点捡起钥匙
}
if(g[k.x][k.y]>='A'&&g[k.x][k.y]<='Z')
{
int p = k.k&(1<<(g[k.x][k.y]-'A'));//走到门处匹配钥匙
if(p==0) continue;//没有钥匙直接进入下次循环
}
if(use[k.x][k.y][k.k]==-1||use[k.x][k.y][k.k]>use[t.x][t.y][t.k]+1)//第一个条 件保证BFS,第二个条件保证不走墙
{
use[k.x][k.y][k.k]=use[t.x][t.y][t.k]+1;
q.push(k);
}
}
}
return -1;
}
有了BFS+状态压缩,写个主函数就可以直接AC了。
主函数
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
scanf("%s",g[i]);
for(int j=0;j<m;j++)
{
if(g[i][j]=='2') {sx=i;sy=j;}//储存起点
if(g[i][j]=='3') {ex=i;ey=j;}//储存终点
}
}
printf("%d\n",bfs());
return 0;
}