题目:Maze
题意:给定一个迷宫的信息,迷宫的最多是50*50的规模,然后有p种钥匙,每种钥匙能够开启对应的门。
x1, y1, x2, y2, g,表示(x1,y1)和(x2,y2)的之间的信息,题目保证(x1,y1)和(x2,y2)一定是相邻的,即上下左右这四种关系之一。g=0表示是墙壁,永远不能通过。g>0表示第g种门,只有当持有第g种钥匙时才能开门通过。
x, y, q,表示在(x,y)这个位置有第q种钥匙。
然后求从左上角(1,1)到达右下角(n,m)的最短时间,不能到达输出-1。
由于门最多10种,所以可以用状态压缩来表示已经获取的钥匙的信息。注意同一个位置可能有多种钥匙。
剩下就是广搜一下,标记好访问过的状态就行了。
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int n, m, p;
int door[51][51][4], map[51][51];
bool vis[51][51][1<<10];
int xl[4]={-1,1,0,0};
int yl[4]={0,0,-1,1};
int getd(int a, int b, int c, int d){
if(a==c){
if(b<d) return 3;
return 2;
}
else{
if(a<c) return 1;
return 0;
}
}
struct Node{
int x, y, st, u;
Node(){}
Node(int x, int y, int st, int u):x(x),y(y),st(st),u(u){}
};
int solve(){
if(n==1 && m==1) return 0;
queue<Node> Q;
Q.push(Node(1,1,map[1][1],0));
while(!Q.empty()){
Node nd = Q.front(); Q.pop();
if(vis[nd.x][nd.y][nd.st]) continue;
vis[nd.x][nd.y][nd.st] = 1;
for(int i=0; i<4; i++){
int a = nd.x+xl[i];
int b = nd.y+yl[i];
if(a<1 || a>n || b<1 || b>m) continue;
if(!door[nd.x][nd.y][i]) continue;
int st = nd.st;
if(door[nd.x][nd.y][i]>0){
int d = 1<<(door[nd.x][nd.y][i]-1);
if(!(st&d)) continue;
}
if(a==n && b==m) return nd.u+1;
st |= map[a][b];
if(!vis[a][b][st]) Q.push(Node(a,b,st,nd.u+1));
}
}
return -1;
}
int main(){
while(~scanf("%d %d %d", &n, &m, &p)){
memset(door, -1, sizeof(door));
memset(map, 0, sizeof(map));
memset(vis, 0, sizeof(vis));
int k;
scanf("%d", &k);
int a, b, c, d, e;
while(k--){
scanf("%d %d %d %d %d", &a, &b, &c, &d, &e);
door[a][b][getd(a,b,c,d)] = e;
door[c][d][getd(c,d,a,b)] = e;
}
scanf("%d", &k);
while(k--){
scanf("%d %d %d", &a, &b, &c);
map[a][b] |= (1<<(c-1));
}
printf("%d\n", solve());
}
return 0;
}