全源最短路问题
当 n 很小时,可以跑 Floyd
无负边权的图直接跑 n 轮 Dijkstra。
存在负边权的图无法跑 Dijkstra,n 轮 SPFA 可被特殊数据卡掉,将图转换为无负权边的图再跑 Dijkstra。
做法:
建立超级源S,到每个点连长度为 0 的单向边。以 S 为起点跑最短路,得到到节点 i 的距离 f[i]。
对于 edge(u, v, dis):
由最短路性质可知,f[u] + dis >= f[v]
所以 dis + f[u] - f[v] 的值始终 >= 0,将每条边的边权替换为 dis + f[u] - f[v] 可保证边权为 >= 0,此时可跑 Dijkstra。
对于起点 u 和终点 v,d[v] = edge1.dis + f[u] - … - f[v] + edge[x].dis,距离始终为 d[v] + f[v] - f[u],与路径无关,故正确性得到保证。
洛谷P5905模板
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
#define ll long long
const int maxn = 3010;
const int maxm = 6010;
const int inf = 1e9;
struct node {
int to;
ll dis;
node(int to, ll dis) :to(to), dis(dis) {}
bool operator<(const node& other)const {
return dis > other.dis;
}
};
vector<node> G[maxn];
int n, m;
ll f[maxn];
int cnt[maxn];
bool inq[maxn];
queue<int> q;
bool SPFA() {
for (int i = 1; i <= n; ++i) {
G[0].push_back(node(i, 0));
f[i] = inf;
}
inq[0] = true;
q.push(0);
while (!q.empty()) {
int u = q.front(); q.pop();
inq[u] = false;
for (int i = 0; i < G[u].size(); ++i) {
node& e = G[u][i];
if (f[e.to] > f[u] + e.dis) {
f[e.to] = f[u] + e.dis;
if (!inq[e.to]) {
q.push(e.to);
inq[e.to] = true;
if (++cnt[e.to] > n) {
return false;
}
}
}
}
}
return true;
}
ll d[maxn];
bool done[maxn];
priority_queue<node> pq;
ll dijkstra(int s) {
for (int i = 1; i <= n; ++i) {
d[i] = inf;
done[i] = false;
}
d[s] = 0;
pq.push(node(s, 0));
while (!pq.empty()) {
int u = pq.top().to; pq.pop();
if (done[u]) {
continue;
}
done[u] = true;
for (int i = 0; i < G[u].size(); ++i) {
node& e = G[u][i];
if (!done[e.to] && d[u] != inf) {
if ( d[e.to] > d[u] + e.dis - (f[e.to] - f[u])) {
d[e.to] = d[u] + e.dis - (f[e.to] - f[u]);
pq.push(node(e.to, d[e.to]));
}
}
}
}
ll sum = 0;
for (int i = 1; i <= n; ++i) {
if (d[i] != inf) {
sum += i * (d[i] - (f[s] - f[i]));
}
else {
sum += (ll)i * inf;
}
}
return sum;
}
int main(){
scanf("%d%d", &n, &m);
int u, v, w;
while (m--) {
scanf("%d%d%d", &u, &v, &w);
G[u].push_back(node(v, w));
}
if (SPFA()) {
for (int i = 1; i <= n; ++i) {
printf("%lld\n", dijkstra(i));
}
}
else {
printf("-1\n");
}
return 0;
}