题目描述 https://www.luogu.org/problemnew/show/P4011
这道题看起来很复杂,有各种的门和钥匙,还有过不去的墙。仔细分析还是可以做出来的。
先说明一下数组的含义
1.用map[x][y][xx][yy]表示坐标(x,y)与坐标(xx,yy)之间有墙还是钥匙,-1为墙,是几就是有几号的门。
2.ky[x][y][num[x][y]]表示(x,y)上第num[x][y]把钥匙。
3.fl[x][y][k]标记数组,k为钥匙的状态
本题要用到优先队列,比较方便
注意:无法走出要输出-1
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int map[15][15][15][15],ky[15][15][150],num[15][15];
int n,m;
bool fl[15][15][(1<<15)];//标记 最后一位为钥匙的状态
struct mp{
int x,y,step,key;//位置 步数 钥匙的状态
};
queue <mp> d;
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
int bfs()
{
int nows=0;
for(int i=1;i<=num[1][1];i++)
nows|=(1<<(ky[1][1][i]-1));//将第一格的钥匙记录下来
fl[1][1][nows]=1;//做标记
d.push((mp){1,1,0,nows});
while(!d.empty())
{
mp now=d.front();
d.pop();
if(now.x==n&&now.y==m) return now.step;
for(int i=0;i<=3;i++)
{
int xx=now.x+dx[i];
int yy=now.y+dy[i];
if(xx<1||xx>n||yy<1||yy>m) continue;
int t=map[now.x][now.y][xx][yy];
if(t==-1) continue;//有墙
if((t!=0)&&((now.key&(1<<(t-1)))==0)) continue;//有门但没有门的钥匙
int kk=now.key;//当前有的钥匙状态
for(int j=1;j<=num[xx][yy];j++)
kk|=(1<<(ky[xx][yy][j]-1));//加上这一格的钥匙
if(fl[xx][yy][kk]==1) continue;
fl[xx][yy][kk]=1;
d.push((mp){xx,yy,now.step+1,kk});
}
}
return -1;//无法走出
}
int main()
{ int p,k,s;
scanf("%d%d%d",&n,&m,&p);
scanf("%d",&k);
while(k--)
{
int x,y,xx,yy,g;
scanf("%d%d%d%d%d",&x,&y,&xx,&yy,&g);
if(g==0) map[x][y][xx][yy]=map[xx][yy][x][y]=-1;//有墙
else map[x][y][xx][yy]=map[xx][yy][x][y]=g;//有g号门
}
scanf("%d",&s);
while(s--)
{
int x,y,p;
scanf("%d%d%d",&x,&y,&p);
ky[x][y][++num[x][y]]=p;//(x,y)上第num[x][y]把钥匙为p号钥匙
}
printf("%d",bfs());
return 0;
}