题意:给你一个n*m的迷宫,地图中有一些障碍不能走,还有p种门,要过门首先得拿到跟这扇门同类型的钥匙。
问从(1,1)到(n,m)最短时间。(1<= n, m <=50, 0<= p <=10)
思路:没有门的时候都会做,一个bfs就行,现在只不过是多了门这种情况。
解决办法:
book[x][y][sta] 表示(x, y)这个点在sta状态下是否已经走过,sta表示拥有钥匙情况。
bar[x1][y1][x2][y2] 表示(x1, y1)到(y1, y2)是否有墙
sth[x1][y1][x2][y2] 表示(x1, y1)到(x2, y2)存在哪种门,0表示没有
key[x][y] 表示(x, y)处有什么钥匙
有了这些处理,再去做bfs就可以了。
注意有些点可能有多个钥匙;墙和门是双向的。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 51;
const int maxm = 11;
bool book[maxn][maxn][1<<maxm];
bool bar[maxn][maxn][maxn][maxn];
int sth[maxn][maxn][maxn][maxn];
int key[maxn][maxn];
int n, m, p, k; //k men\qiang, p kind
struct node
{
int x, y, t, k;
node() {}
node(int xx, int yy, int tt, int kk): x(xx), y(yy), t(tt), k(kk) {}
};
int bfs()
{
int Next[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
memset(book, 0, sizeof(book));
queue<node> q;
int tmp = 0;
if(key[1][1])
tmp |= key[1][1];
q.push(node(1, 1, 0, tmp));
book[1][1][tmp] = 1;
while(!q.empty())
{
node u = q.front(); q.pop();
int x = u.x, y = u.y, t = u.t, k = u.k;
if(x == n && y == m) return t;
for(int i = 0; i < 4; i++)
{
int tx = x+Next[i][0];
int ty = y+Next[i][1];
if(tx >= 1 && ty >= 1 && tx <= n && ty <= m && !bar[x][y][tx][ty] && !book[tx][ty][k])
{
if(!sth[x][y][tx][ty] || (k>>(sth[x][y][tx][ty]-1))&1)
{
book[tx][ty][k] = 1;
book[tx][ty][k|key[tx][ty]] = 1;
q.push(node(tx, ty, t+1, k|key[tx][ty]));
}
}
}
}
return -1;
}
int main(void)
{
while(cin >> n >> m >> p)
{
memset(key, 0, sizeof(key));
memset(bar, 0, sizeof(bar));
memset(sth, 0, sizeof(sth));
scanf("%d", &k);
for(int i = 1; i <= k; i++)
{
int x1, y1, x2, y2, z;
scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &z);
if(!z) bar[x1][y1][x2][y2] = bar[x2][y2][x1][y1] = 1;
else sth[x1][y1][x2][y2] = sth[x2][y2][x1][y1] = z;
}
scanf("%d", &k);
for(int i = 1; i <= k; i++)
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
key[x][y] |= (1<<(z-1));
}
printf("%d\n", bfs());
}
return 0;
}