题目链接:https://www.luogu.com.cn/problem/P5340
解题思路:
拆点/分层图最短路。
每个点 \(u\) 及到达点 \(u\) 是所吃汉堡与所喝可乐数量之差 \(p\) 对应一个二元组 \((u,p)\)。对二元组求最短路。
示例程序:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 10100;
struct Edge {
int v, w;
Edge() {}
Edge(int _v, int _w) { v = _v; w = _w; }
};
vector<Edge> g[maxn];
int dis[maxn][21], T, n, m, k, a[maxn], s, t;
bool vis[maxn][21];
struct Node {
int u, p, w;
Node() {}
Node(int _u, int _p, int _w) { u = _u; p = _p; w = _w; }
bool operator < (const Node & b) const {
return w > b.w;
}
};
priority_queue<Node> que;
int main() {
ios::sync_with_stdio(0);
cin >> T;
while (T --) {
cin >> n >> m >> k;
for (int i = 1; i <= n; i ++) {
for (int j = 0; j <= 2*k; j ++) {
dis[i][j] = -1;
vis[i][j] = false;
}
}
for (int i = 1; i <= n; i ++) {
cin >> a[i];
g[i].clear();
}
while (m --) {
int u, v, w;
cin >> u >> v >> w;
g[u].push_back(Edge(v, w));
g[v].push_back(Edge(u, w));
}
cin >> s >> t;
dis[s][k+(a[s]==1 ? 1 : -1)] = 0;
que.push(Node(s, (a[s]==1 ? 1 : -1), 0));
while (!que.empty()) {
Node nd = que.top();
que.pop();
int u = nd.u, p = nd.p, w = nd.w;
if (vis[u][k+p]) continue;
vis[u][k+p] = true;
for (auto e : g[u]) {
int v = e.v;
int pp = p + (a[v]==1 ? 1 : -1);
if (pp >= -k && pp <= k && (dis[v][k+pp] == -1 || dis[v][k+pp] > w + e.w)) {
dis[v][k+pp] = w + e.w;
que.push(Node(v, pp, w+e.w));
}
}
}
int ans = -1;
for (int i = -k; i <= k; i ++) {
if (dis[t][k+i] != -1 && (ans == -1 || ans > dis[t][k+i]))
ans = dis[t][k+i];
}
cout << ans << endl;
}
return 0;
}