与一般的bfs不一样的是,这里标记走过的路为三维数组sign[x][y][k],代表的是,在x,y这个点,拥有k状态的钥匙情况是否访问过。
由于只有10把钥匙,用二进制的 | & 操作判断钥匙 和门。
例如:000000001为有第一把钥匙 ,1000000000为有第十把钥匙。
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
char grap[25][25];
int sign[25][25][5000]; <span style="white-space:pre"> </span>//注意,这里要大于2048,一开始开的2000,wa了n次<span style="white-space:pre"> </span>
int ex,ey,sx,sy;
int m,n,t,ans;
int dir[5][2]={0,0,1,0,-1,0,0,1,0,-1};
typedef struct ac
{
int x,y,k,time;
}node;
void bfs(int x,int y,int time)
{
queue <node >q;
node next,temp;
next.x=x;
next.y=y;
next.k=0;
next.time=time;
q.push(next);
while(!q.empty())
{
next=q.front();
q.pop();
if(next.time>=t)<span style="white-space:pre"> </span>//超时跳出
return ;
if(next.x==ex && next.y==ey)<span style="white-space:pre"> </span>//到终点
{
ans=next.time;
return ;
}
for(int i=1;i<=4;i++)
{
temp.x=next.x+dir[i][0];
temp.y=next.y+dir[i][1];
temp.k=next.k;
temp.time=next.time+1;
if(temp.x<1 ||temp.x>n || temp.y<1 || temp.y>m || grap[temp.x][temp.y]=='*') //出界,撞墙
continue;
if(grap[temp.x][temp.y]>='a' && grap[temp.x][temp.y]<='z')//钥匙,k记录钥匙
{
temp.k|=(1<<(grap[temp.x][temp.y]-'a'+1));
if(sign[temp.x][temp.y][temp.k]==0)<span style="white-space:pre"> </span>//判断这个状态是否访问过
{
sign[temp.x][temp.y][temp.k]=1;
q.push(temp);
}
}
else if(grap[temp.x][temp.y]>='A' && grap[temp.x][temp.y]<='Z') //门
{
int k=temp.k&(1<<(grap[temp.x][temp.y]-'A'+1));
if(sign[temp.x][temp.y][temp.k]==0 && k)<span style="white-space:pre"> </span>//判断是否访问,及是否有该门的钥匙
{
sign[temp.x][temp.y][temp.k]=1;
q.push(temp);
}
}
else if(sign[temp.x][temp.y][temp.k]==0)<span style="white-space:pre"> </span>//普通的路,判断是否访问
{
sign[temp.x][temp.y][temp.k]=1;
q.push(temp);
}
}
}
}
int main()
{
int i,j;
while(scanf("%d %d %d",&n,&m,&t)!=EOF)
{
for(i=1;i<=n;i++)
{
scanf("%s",&grap[i][1]);
for(j=1;j<=m;j++)
{
if(grap[i][j]=='@')
sx=i,sy=j;
else if(grap[i][j]=='^')
ex=i,ey=j;
}
}
ans=-1;
memset(sign,0,sizeof(sign));<span style="white-space:pre"> </span>//注意每次置零
bfs(sx,sy,0);
printf("%d\n",ans);
}
return 0;
}