#6121. 「网络流 24 题」孤岛营救问题 迷宫 分层图

题目链接
题意
一个有n*m个方格的迷宫,相邻的方格之间可能是墙,也可能是连通的,也可能是门,门有多种类型,需要对应类型的钥匙才可以通过,某些方格里存放着钥匙,问从左上角(1,1)到(n,m)最短的时间。
思路
分层图,以携带的钥匙为层数,用二进制法存,按题意建图后跑spfa。

#include 
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 2e2 + 7;
const int maxm = 5e3 + 7;
typedef long long ll;
int key[maxn * maxn], dis[maxm][maxn];
int id[maxn][maxn], head[maxn * maxn], mp[maxn][maxn], to[maxn*maxn], nex[maxn*maxn], edge[maxn*maxn];
int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
struct node {
    int x, v;
    node(int a, int b): x(a), v(b){}
};
int n, m, s, t, cnt;
void init()
{
    cnt = 0; s = 1; t = n * m;
    memset(head, -1, sizeof(head));
    memset(mp, -1, sizeof(mp));
    memset(key, 0, sizeof(key));
}
void add(int x, int y, int w)
{
    to[cnt] = y;
    edge[cnt] = w;
    nex[cnt] = head[x];
    head[x] = cnt++;
}
int spfa()
{
    queue<node> que;
    memset(dis, INF, sizeof(dis));
    dis[1][s] = 0;
    que.push(node(1, s));
    while (!que.empty())
    {
        node now = que.front(); que.pop();
        int u = now.v;
        dis[now.x | key[u]][u] = min(dis[now.x | key[u]][u], dis[now.x][u]);
        now.x |= key[u];
        for (int i = head[u]; ~i; i = nex[i]) {
            int v = to[i];
            if((now.x&edge[i]) == edge[i]) {
                if(dis[now.x][v] > dis[now.x][u] + 1) {
                    dis[now.x][v] = dis[now.x][u] + 1;
                    que.push(node(now.x, v));
                }
            }
        }
    }
    int ans = INF;
    for (int i = 1; i < 5005; i++)
        ans = min(ans, dis[i][t]);
    if(ans == INF) return -1;
    return ans;
}
int main()
{
    int x1, x2, y1, y2, z, p, k, len = 0;
    scanf("%d%d%d%d", &n, &m, &p, &k);
    init();
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            id[i][j] = ++len;
    for (int i = 1; i <= k; i++) {
        scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &z);
        int u = id[x1][y1], v = id[x2][y2];
        mp[u][v] = mp[v][u] = z;
        if(z) add(u, v, 1<<z), add(v, u, 1<<z);
    }
    scanf("%d", &k);
    for (int i = 1; i <= k; i++) {
        scanf("%d%d%d", &x1, &y1, &z);
        key[id[x1][y1]] |= 1<<z;
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            int u = id[i][j];
            for (k = 0; k < 4; k++) {
                int x = i + dx[k], y = j + dy[k];
                int v = id[x][y];
                if(mp[u][v] == -1 && id[x][y])
                    add(u, v, 1);
            }
        }
    }
    printf("%d\n", spfa());
    return 0;
}

你可能感兴趣的:(网络流)