这个故事发生在“星际迷航”的背景下。
“星际争霸”的副队长史波克落入克林贡的诡计中,被关押在他们的母亲星球Qo'noS上。
企业的上尉詹姆斯·T·柯克(James T. Kirk)不得不乘宇宙飞船去救他的副手。幸运的是,他偷走了史波克所在的迷宫地图。
迷宫是一个矩形,它有n行垂直和m列水平,换句话说,它被分为n * m个位置。有序对(行号,列号)表示迷宫中的位置。柯克从当前位置移动到下一个花费1秒。而且他只有在以下情况下才能移动到下一个位置:
下一个位置与当前柯克的位置相邻(上下或左右)(4个方向)
开着的门是可以通行的,但锁着的门不是。
柯克不能通过一堵墙
有几种门是默认锁定的。钥匙只能打开相同类型的门。柯克必须在打开相应的门之前拿到钥匙,这样很浪费时间。
柯克的初始位置是(1,1),而史波克位于(n,m)的位置。你的任务是帮助Kirk尽快找到史波克。
Input
输入包含很多测试用例。
每个测试用例由几行组成。第一行中有三个整数,分别代表n,m和p (1<= n, m <=50, 0<= p <=10).
第二行只列出一个整数k,表示门和墙的总数(0<= k <=500).
在下面的k行中有5个整数,表示 i1, y i1, x i2, y i2, g i; 当g i >=1,表示在位置 (x i1, y i1) 和 (x i2, y i2)之间存在类型gi的门;当g i = 0, 之间存在一个墙(x i1, y i1)和 (x i2, y i2), ( | x i1 - x i2 | + | y i1 - y i2 |=1, 0<= g i <=p )
下面的行是一个整数S,表示迷宫中的钥匙的总数。(0<= S <=50).
在下面的S行中有三个整数,分别表示x i1, y i1和q i这意味着类型为qi的钥匙位于位置 i (x i1, y i1), (1<= q i<=p).
Output
输出Kirk可能达到史波克的可能最小的秒数。
如果没有可能的计划,输出-1。
Sample Input
4 4 9
9
1 2 1 3 2
1 2 2 2 0
2 1 2 2 0
2 1 3 1 0
2 3 3 3 0
2 4 3 4 1
3 2 3 3 0
3 3 4 3 0
4 3 4 4 0
2
2 1 2
4 2 1
Sample Output
14
思路:状态压缩dp+bfs
vis[x][y][k]:用来记录走到(x,y)钥匙状态为k是否访问过。这里压缩的就是钥匙的状态。
注意点:
1、若门是通的,那么只要该状态没有被访问过就可以。
2、若门是锁住的,那么必须先有钥匙才可以通过。
#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
int n,m,p,k,x3,y3,x2,y2,g,s,x,y,q;
struct node{
int x,y,key,cos;
};
int wall[55][55][55][55],keys[55][55],vis[55][55][1<<11];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
void bfs(){
queue<node>q;
vis[1][1][keys[1][1]]=1;
q.push((node){1,1,keys[1][1],0});
while(!q.empty()){
node t=q.front(); q.pop();
int x=t.x, y=t.y;
if(x==n&&y==m){
cout<<t.cos<<endl;
return;
}
for(int i=0; i<4; i++){
int xx=x+dx[i],yy=y+dy[i];
if(xx<1||yy<1||xx>n||yy>m||wall[xx][yy][x][y]==0)continue;
int door=wall[x][y][xx][yy];
int key=t.key,ke=key|keys[xx][yy];
//1、假如没有门,并且没有访问过
//2.有门,且有钥匙开门 ,并且没有访问过
//两种情况合并如下
if((((key&(1<<(door-1)))&&door>0)||door==-1)&&vis[xx][yy][ke]==0){
vis[xx][yy][ke]=1;
q.push((node){xx,yy,ke,t.cos+1});
}
}
}
cout<<-1<<endl;
}
int main()
{
while(cin>>n>>m>>p){
cin>>k;
memset(wall,-1,sizeof(wall));
memset(vis,0,sizeof(vis));
memset(keys,0,sizeof(keys));
for(int i=1; i<=k; i++){
cin>>x3>>y3>>x2>>y2>>g;
wall[x3][y3][x2][y2]=wall[x2][y2][x3][y3]=g;//门可以双向
}
cin>>s;
for(int i=1; i<=s; i++){
cin>>x>>y>>q;
keys[x][y]|=1<<(q-1);//可能同一个位置有多吧钥匙
}
bfs();
}
return 0;
}