「笔记」Johnson 全源最短路与 Primal-Dual 原始对偶算法
写在前面
妈的我的网络流板子常数怎么这么 tama 的大
上网找牛逼板子的时候看到了 Primal-Dual 原始对偶算法觉得很牛逼,抄!
然后发现这东西和 Johnson 思想基本一致,于是顺带着把 Johnson 也学一下。
Johnson 全源最短路
StudyingFather 写太好了,感觉我都没必要写了。扔一份代码在这里算了。
复制复制// /* By:Luckyblock https://www.luogu.com.cn/problem/P5905 */ #include <bits/stdc++.h> #define LL long long #define pli std::pair<LL,int> #define mp std::make_pair const int kN = 3e3 + 10; const int kM = 1e5 + 10; const int kInf = 1e9; //============================================================= int n, m; int edgenum, head[kN], v[kM], ne[kM]; int cnt[kN]; bool vis[kN]; LL w[kM], h[kN], dis[kN]; //============================================================= void Add(int u_, int v_, int w_) { v[++ edgenum] = v_; w[edgenum] = w_; ne[edgenum] = head[u_]; head[u_] = edgenum; } bool Spfa(int s_) { std::queue <int> q; for (int i = 0; i <= n; ++ i) { cnt[i] = vis[i] = 0; h[i] = kInf; } q.push(s_); h[s_] = 0; vis[s_] = true; while (!q.empty()) { int u_ = q.front(); q.pop(); vis[u_] = false; for (int i = head[u_]; i; i = ne[i]) { int v_ = v[i], w_ = w[i]; if (h[u_] + w_ < h[v_]) { h[v_] = h[u_] + w_; cnt[v_] = cnt[u_] + 1; if (cnt[v_] > n) return false; if (!vis[v_]) q.push(v_), vis[v_] = true; } } } return true; } void Dijkstra(int s_) { std::priority_queue<pli> q; for (int i = 1; i <= n; ++ i) { vis[i] = 0, dis[i] = kInf; } dis[s_] = 0; q.push(mp(0, s_)); while (!q.empty()) { int u_ = q.top().second; q.pop(); if (vis[u_]) continue; vis[u_] = true; for (int i = head[u_]; i; i = ne[i]) { int v_ = v[i], w_ = w[i]; if (dis[u_] + w_ < dis[v_]) { dis[v_] = dis[u_] + w_; q.push(mp(-dis[v_], v_)); } } } } //============================================================= int main() { //freopen("1.txt", "r", stdin); std::ios::sync_with_stdio(0), std::cin.tie(0); std::cin >> n >> m; for (int i = 1; i <= m; ++ i) { int u_, v_, w_; std::cin >> u_ >> v_ >> w_; Add(u_, v_, w_); } for (int i = 1; i <= n; ++ i) Add(0, i, 0); if (!Spfa(0)) { std::cout << -1 << "\n"; return 0; } for (int u = 1; u <= n; ++ u) { for (int i = head[u]; i; i = ne[i]) { w[i] += h[u] - h[v[i]]; } } for (int i = 1; i <= n; ++ i) { Dijkstra(i); LL ans = 0; for (int j = 1; j <= n; ++ j) { if (dis[j] == kInf) ans += 1ll * j * kInf; else ans += 1ll * j * (dis[j] + h[j] - h[i]); } std::cout << ans << "\n"; } return 0; }
Primal-Dual 原始对偶算法
// /* By:Luckyblock https://www.luogu.com.cn/problem/P3381 */ #include <bits/stdc++.h> #define LL long long #define pli std::pair<LL,int> #define mp std::make_pair const int kN = 5e3 + 10; const int kM = 2e5 + 10; const LL kInf = 1e18 + 2077; //============================================================= int n, m, S, T; int edgenum = 1, head[kN], v[kM], ne[kM]; bool vis[kN]; LL w[kM], c[kM], h[kN], dis[kN]; LL maxf, minc; struct Previous_Node { int node, edge; } from[kN]; //============================================================= void Add(int u_, int v_, LL w_, LL c_) { v[++ edgenum] = v_; w[edgenum] = w_; c[edgenum] = c_; ne[edgenum] = head[u_]; head[u_] = edgenum; } void Spfa(int s_) { std::queue <int> q; for (int i = 0; i <= n; ++ i) { vis[i] = 0; h[i] = kInf; } q.push(s_); h[s_] = 0; vis[s_] = true; while (!q.empty()) { int u_ = q.front(); q.pop(); vis[u_] = false; for (int i = head[u_]; i; i = ne[i]) { int v_ = v[i], w_ = w[i], c_ = c[i]; if (w_ && h[u_] + c_ < h[v_]) { h[v_] = h[u_] + c_; if (!vis[v_]) q.push(v_), vis[v_] = true; } } } } bool Dijkstra(int s_) { std::priority_queue<pli> q; for (int i = 1; i <= n; ++ i) { vis[i] = 0, dis[i] = kInf; } dis[s_] = 0; q.push(mp(0, s_)); while (!q.empty()) { int u_ = q.top().second; q.pop(); if (vis[u_]) continue; vis[u_] = true; for (int i = head[u_]; i; i = ne[i]) { int v_ = v[i], w_ = w[i], nc_ = c[i] + h[u_] - h[v_]; if (w_ && dis[u_] + nc_ < dis[v_]) { dis[v_] = dis[u_] + nc_; from[v_] = (Previous_Node) {u_, i}; if (!vis[v_]) q.push(mp(-dis[v_], v_)); } } } return dis[T] != kInf; } void MCMF() { Spfa(S); while (Dijkstra(S)) { LL minf = kInf; for (int i = 1; i <= n; ++ i) h[i] += dis[i]; for (int i = T; i != S; i = from[i].node) minf = std::min(minf, w[from[i].edge]); for (int i = T; i != S; i = from[i].node) { w[from[i].edge] -= minf; w[from[i].edge ^ 1] += minf; } maxf += minf; minc += minf * h[T]; } return ; } //============================================================= int main() { // freopen("1.txt", "r", stdin); std::ios::sync_with_stdio(0), std::cin.tie(0); std::cin >> n >> m >> S >> T; for (int i = 1; i <= m; ++ i) { int u_, v_, w_, c_; std::cin >> u_ >> v_ >> w_ >> c_; Add(u_, v_, w_, c_); Add(v_, u_, 0, -c_); } MCMF(); std::cout << maxf << " " << minc; return 0; }
写在最后
参考:
作者@Luckyblock,转载请声明出处。