費用流去掉負權邊
阿新 • • 發佈:2022-01-06
消去網路中負權邊的方法。
首先不能給邊勢能函式,因為最短路的路徑不一定一致。於是在點上做文章,給每個點一個勢能函式 \(h(x)\),滿足 \(\forall (x,y)\in E,s.t.h(x)-h(y)+w(x,y)\geqslant0\),這樣跑出來的最短路多的權就是 \(h(s)-h(t)\)。
至於構造方法,每次增廣完以後,如果 \((x,y)\in E_r\),則 \(y\) 一定是 \(x\) 的 successor(不然就不在增廣路上),也就是說 \(d_x+w(x,y)+h(x)-h(y)=d_y\),其中 \(d\) 是 \(s\) 到該點的最短路,可得 \((d_y+h(y))-(d_x+h(x))=w(x,y)\)
那麼令 \(h(x):=h(x)+d(x)\) 即可。
template<typename type1, typename type2, const int N, const int M, const type1 inf1 = numeric_limits<type1>::max(), const type2 inf2 = numeric_limits<type2>::max()> struct SSP { struct edge { int to, nxt; type1 c; type2 f; }; int head[N], vis[N], tot, id[N], pre[N]; type2 dis[N], h[N]; edge e[M<<1]; void clear(const int n) { tot = 1; memset(head+1, 0, n<<2); } void link(const int x, const int y, type1 c, type2 f) { e[++tot] = (edge){y, head[x], c, f},head[x] = tot; e[++tot] = (edge){x, head[y], 0, -f},head[y] = tot; } void Spfa(const int s, const int t, const int n) { queue<int> q; fill(h+1, h+n+1, inf2); memset(vis+1, 0, n<<2); for(q.push(s), vis[s] = 1, h[s] = 0; q.size(); vis[q.front()] = 0, q.pop()) { for(int now = q.front(), i = head[now], y; i; i = e[i].nxt) { if(e[i].c && (h[y = e[i].to] == inf2 || h[y] > h[now]+e[i].f)) { h[y] = h[now]+e[i].f; if(!vis[y]) q.push(y),vis[y] = 1; } } } } bool Dij(const int s, const int t, const int n) { priority_queue<pair<type2, int>, vector<pair<type2, int>>, greater<pair<type2, int>>> q; fill(dis+1, dis+n+1, inf2); memset(vis+1, 0, n<<2); for(q.emplace(dis[s] = 0, s); q.size();) { int now = q.top().second; q.pop(); if(vis[now]) continue; vis[now] = 1; for(int i = head[now], y; i; i = e[i].nxt) { if(e[i].c && (dis[y = e[i].to] == inf2 || dis[y] > dis[now]+e[i].f+h[now]-h[y])) { dis[y] = dis[now]+e[i].f+h[now]-h[y]; pre[y] = now,id[y] = i; if(!vis[y]) q.emplace(dis[y], y); } } } return dis[t] < inf2; } pair<type1, type2> get(const int s, const int t, const int n) { type1 res1 = 0; type2 res2 = 0; Spfa(s, t, n); while(Dij(s, t, n)) { type1 cur = inf1; for(int i = 1; i <= n; ++i) h[i] += dis[i]; for(int i = t; i != s; i = pre[i]) cmin(cur, e[id[i]].c); for(int i = t; i != s; i = pre[i]) e[id[i]].c -= cur,e[id[i]^1].c += cur; res1 += cur,res2 += cur*h[t]; } return make_pair(res1, res2); } };