洛谷P7297 [USACO21JAN] Telephone G 题解 分层图最短路

题目链接:https://www.luogu.com.cn/problem/P7297

解题思路:

对于每个颜色 \(c\),在第 \(c\) 层作出一条链,对于 \(1 \le i \lt n\)\((i,c)\)\((i,c+1)\) 之间有一条权值为 \(1\) 的双向边。

\((i,0)\)\((i, b_i)\) 连一条权值为 \(0\) 的有向边。

对于所有 \(S_{c, b_i} = 1\) 的颜色 \(c\),从 \((i,c)\) 连向 \((i, 0)\) 一条权值为 \(0\) 的有向边。

\((1, 0)\) 为起点 \((n, 0)\) 为终点求最短路。

示例程序(需要开 O2 优化):

#include <bits/stdc++.h>
using namespace std;
const int maxn = 50050;

int n, K, b[maxn], dis[maxn * 55];
struct Edge {
    int v, w;
    Edge() {}
    Edge(int _v, int _w) { v = _v; w = _w; }
};
vector<Edge> g[maxn * 55];
char color[55][55];
bool vis[maxn * 55];

struct Node {
    int u, dis;
    bool operator < (const Node& b) const {
        return dis > b.dis;
    }
};
priority_queue<Node> que;

int ha(int u, int k) {
    return k * n + u;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie();
    cin >> n >> K;
    for (int i = 1; i < n; i ++) {
        for (int j = 1; j <= K; j ++) {
            g[ha(i, j)].push_back({ha(i+1, j), 1});
            g[ha(i+1, j)].push_back({ha(i, j), 1});
        }
    }
    for (int i = 1; i <= n; i ++) cin >> b[i];
    for (int i = 1; i <= K; i ++) cin >> color[i]+1;
    for (int i = 1; i <= n; i ++) {
        g[ha(i, 0)].push_back({ha(i, b[i]), 0});
        for (int j = 1; j <= K; j ++) if (color[j][b[i]] == '1') g[ha(i, j)].push_back({ha(i, 0), 0});
    }
    memset(dis, -1, sizeof(dis));
    que.push({ha(1, 0), 0});
    dis[ha(1, 0)] = 0;
    while (!que.empty()) {
        Node nd = que.top();
        que.pop();
        int u = nd.u, d = nd.dis;
        if (vis[u]) continue;
        vis[u] = true;
        if (u == ha(n, 0)) break;
        for (auto e : g[u]) {
            int v = e.v, w = e.w;
            if (dis[v] == -1 || dis[v] > d + w) {
                dis[v] = d + w;
                que.push({v, d+w});
            }
        }
    }
    cout << dis[ha(n, 0)] << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/quanjun/p/15564130.html