题解:https://blog.youkuaiyun.com/u014303647/article/details/38658991
思路来自上面这篇大佬的题解,解题思路源自上面这篇题解
- 解题关键在于:如何表示是否带了钥匙
- 一共有10把钥匙,共有1024种状态,用二进制表示
j | i | h | g | f | e | d | c | b | a |
- 每个点包括:横坐标、纵坐标、到达该点的时间、到达该点时带的钥匙的状态
- 定义一个judge函数,用于判断下一个点是否能走,不能超过边界,不能是墙,不能超过t(不包括t),带着当前钥匙状态没有访问过该点
- bfs(起点,终点)
- 满足judge的情况下,如果遇到钥匙a-j,就 |(或)对应的二进制数,携带上钥匙。如果遇到门,就用当前带的钥匙状态&(与)门对应的二进制数,试能不能开门。不能开门就continue.
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define maxn 20
char map1[maxn+5][maxn+5];
int visit[maxn+5][maxn+5][1030];
int n,m,t;
int zx[]={0,0,-1,1};
int zy[]={-1,1,0,0};
struct zuobiao
{
int x;
int y;
int time;
int key;
}in,out;
bool judge(zuobiao p)
{
if(p.x>=0&&p.x<n&&p.y>=0&&p.y<m&&map1[p.x][p.y]!='*'&&p.time<t)
{
if(!visit[p.x][p.y][p.key])
return true;
else
return false;
}
else
return false;
}
void bfs(zuobiao f,zuobiao g)
{
queue<zuobiao>q;
f.time=0;
f.key=0;
q.push(f);
visit[f.x][f.y][0]=1;
while(!q.empty())
{
f=q.front();
q.pop();
zuobiao lu;
for(int i=0;i<4;i++)
{
lu=f;
lu.x+=zx[i];
lu.y+=zy[i];
lu.time++;
if(judge(lu))
{
int x=1;
if(map1[lu.x][lu.y]>='a'&&map1[lu.x][lu.y]<='z')
{
x=x<<(map1[lu.x][lu.y]-'a');
lu.key=lu.key|x;
}
else if(map1[lu.x][lu.y]>='A'&&map1[lu.x][lu.y]<='Z')
{
if(!(lu.key&(x<<(map1[lu.x][lu.y]-'A'))))
continue;
}
visit[lu.x][lu.y][lu.key]=1;
q.push(lu);
if(lu.x==g.x&&lu.y==g.y)
{
printf("%d\n",lu.time);
return ;
}
}
}
if(q.empty())
printf("-1\n");
}
}
int main()
{
while(scanf("%d %d %d",&n,&m,&t)!=EOF)
{
memset(visit,0,sizeof(visit));
char s;
for(int i=0;i<n;i++)
{
scanf("%c",&s);
for(int j=0;j<m;j++)
{
scanf("%c",&map1[i][j]);
if(map1[i][j]=='@')
{
in.x=i;
in.y=j;
}
else if(map1[i][j]=='^')
{
out.x=i;
out.y=j;
}
}
}
visit[in.x][in.y][0]=1;
bfs(in,out);
}
return 0;
}