题目链接:https://www.luogu.com.cn/problem/P1073
解题思路:
将每个点 \(u\),拆成三层:
- 第 \(0\) 层:\((u, 0)\);
- 第 \(1\) 层:\((u, 1)\);
- 第 \(2\) 层:\((u, 2)\)。
各层之间依次建图。
然后对于任意点 \(u\),设点 \(u\) 的权值为 \(a_u\),则:
- 从 \((u,0)\) 连 \((u,1)\) 一条权值为 \(a_u\) 的有向边;
- 从 \((u,1)\) 连 \((u,2)\) 一条权值为 \(-a_u\) 的有向边。
(我在实际实现的时候都加上了 \(100\),主要是边权不为负比较好写一点)
求 \((1, 0)\) 到 \((n, 2)\) 的最短路。
示例程序:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int n, m, dis[maxn*3], a[maxn];
struct Edge {
int v, w;
};
vector<Edge> g[maxn*3];
bool vis[maxn*3];
int ha(int i, int j) {
return j * n + i;
}
struct Node {
int u, dis;
bool operator < (const Node& b) const {
return dis > b.dis;
}
};
priority_queue<Node> que;
int main() {
ios::sync_with_stdio(0);
cin >> n >> m;
for (int i = 1; i <= n; i ++)
cin >> a[i];
for (int i = 1; i <= n; i ++) {
g[ha(i, 0)].push_back({ha(i, 1), 100+a[i]});
g[ha(i, 1)].push_back({ha(i, 2), 100-a[i]});
}
while (m --) {
int u, v, z;
cin >> u >> v >> z;
for (int i = 0; i < 3; i ++) {
g[ha(u, i)].push_back({ha(v, i), 0});
if (z == 2)
g[ha(v, i)].push_back({ha(u, i), 0});
}
}
memset(dis, -1, sizeof(dis));
dis[ha(1, 0)] = 0;
que.push({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;
for (auto e : g[u]) {
int v = e.v, w = e.w;
if (!vis[v] && (dis[v] == -1 || dis[v] > d + w)) {
dis[v] = d + w;
que.push({v, dis[v]});
}
}
}
if (dis[ha(n, 2)] == -1) cout << 0 << endl;
else cout << 200 - dis[ha(n, 2)] << endl;
return 0;
}