1. 程式人生 > 其它 >費用流去掉負權邊

費用流去掉負權邊

消去網路中負權邊的方法。

首先不能給邊勢能函式,因為最短路的路徑不一定一致。於是在點上做文章,給每個點一個勢能函式 \(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);
	}
};