集训队作业 2021 #114. Son of Pipe Stream

\(\rm Son ~of ~Pipe~ Stream(DJ)\)

给定一张 \(n\) 个点,\(m\) 条边的图,将这张图进行一次“复制”我们得到了两张完全相同的图,这两张图均以 \(3\) 号点作为汇点,但第一张图以 \(1\) 号节点作为源点,第二张图以第 \(2\) 号节点作为源点。

给定常数 \(v,a\),同时每条边有边权 \(c_i\)

现在,你需要给两张图上的每条边确定一个流量和方向,在两张图上一条边的方向应该是一致的,除源点和汇点每个点需满足流量平衡,同时对于每条边有约束:

  • \(v\cdot f_i+w_i\le c_i\)

其中 \(f_i\) 为第一张图上此边的流量 \(w_i\) 为第二张图上此边的流量。

对于流入汇点的流量,设 \(F\) 为第一张图上流入汇点的流量,\(W\) 为第二张图上流入汇点的流量,你需要最大化 \(F^a\cdot W^{1-a}\)

\(n\le 300,m\le \frac{n(n-1)}{2}\),答案的绝对误差不应超过 \(10^{-4}\)

Solution

考虑 \(\frac{v^aF^aW^{1-a}}{v^a}=\frac{(vF)^aW^{1-a}}{v^a}\)

对于每条边,令 \(f_i'=v\cdot f_i\),限制等价于 \(f_i'+w_i\le c_i\)

考虑怎样的一组 \(F,W\) 是合法的,我们先跑出 \(F\) 的上界 \(F_{\max}\),跑出 \(W\) 的上界 \(W_{\max}\),然后跑出 \(S=(F+W)_{\max}\)

可以证明只要一组 \((F',W')\) 满足此约束那么他都是合法的。

证明:

首先可以证明 \((F_{\max},S-F_{\max})\) 是合法的,因为我们可以先流 \(F_{\max}\),然后再将残余网络给第二部分流,因为不会退流给起始点,又因为我们任意增广总是可以流到最大流,所以 \(S-F_{\max}\) 是一定可以取到的。

类似的,\((S-W_{\max},W_{\max})\) 也可以取到。

对于任意的 \((F',W')\),我们考虑这两张图的流量网络,我们通过 \(\alpha\)\(1-\alpha\) 总是能够组成 \((F',W')\),所以最后的策略为先流 \(\alpha \times (F_{\max},S-F_{\max})+(1-\alpha)\times (S-W_{\max}, W_{\max})\),然后得到答案。

等一下,还有一个限制,两张图上的边必须同向。

可以这样考虑,我们先求出 \(F'\)\(W'\) 然后跑一次最大流。

此时我们重构这张图,每条边的方向为此流的方向,每条边的容量为此流中的容量,然后再从 \(1\) 开始跑一次最大流,将边删掉,就是从 \(2\) 出发的流量了。

然后由于 \(S\) 确定,答案相当于 \((F+W)=S,F^aW^{1-a}\) 的最大值,取在 \(F'=a\cdot S\) 处有最大值。

\(Code:\)

#include<bits/stdc++.h>
using namespace std ;
#define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
#define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
#define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
#define re register
#define mp make_pair
const double inf = 1e9 ; 
const int N = 200 + 5 ; 
const int M = 1e5 + 5 ; 
int n, m, top ; 
struct S { int x, y ; double z ; } s[M], st[M] ;
double K, alpha ; 
map<pair<int, int>, int> sf ; 
map<pair<int, int>, double> dw ; 
map<pair<int, int>, double> cost, FF ; 
struct Flow {
	int S, T, cnt, dep[N], head[N], cur[N] ; 
	struct E {
		int fr, to, next ; double w ; 
	} e[M] ;
	void undir(int x, int y, double z) { //undircet
		e[++ cnt] = (E){ x, y, head[x], z }, head[x] = cnt,
		e[++ cnt] = (E){ y, x, head[y], z }, head[y] = cnt ; 
	}
	void dir(int x, int y, double z) { //dircet
		e[++ cnt] = (E){ x, y, head[x], z }, head[x] = cnt,
		e[++ cnt] = (E){ y, x, head[y], 0 }, head[y] = cnt ; 
	}
	queue<int> q ; 
	bool bfs() {
		rep( i, 0, n ) dep[i] = 0 ; dep[S] = 1, q.push(S) ; 
		while( !q.empty() ) {
			int u = q.front() ; q.pop() ; 
			Next( i, u ) {
				int v = e[i].to ; 
				if( !dep[v] && e[i].w ) 
				dep[v] = dep[u] + 1, q.push(v) ;
			}
		} return (dep[T] != 0);
	}
	double dfs(int x, double dist) {
		if(x == T) return dist ; double flow = 0 ; 
		for(int &i = cur[x]; i; i = e[i].next) {
			int v = e[i].to ; 
			if((dep[v] == dep[x] + 1) && e[i].w ){
				double di = dfs(v, min(dist, e[i].w)) ;
				e[i].w -= di, e[i ^ 1].w += di,
				dist -= di, flow += di ; 
				if( !dist ) return flow ; 
			}
		} return flow ; 
	}
	double dinic() {
		double ans = 0 ;
		while(bfs()) {
			memcpy(cur, head, sizeof(head)) ;
			while(double di = dfs(S, inf)) ans += di ;
		} return ans ; 
	}
	void build() {
		for(re int i = 2; i <= cnt; ++ i ) {
			if( e[i].fr == 0 || e[i].to == 0 ) continue ; 
			double c = dw[mp(e[i].fr, e[i].to)] ;
			if( c <= e[i].w ) continue ;
			c -= e[i].w, ++ top ;
			st[top].x = e[i].fr, st[top].y = e[i].to, st[top].z = c ; 
			cost[mp(e[i].fr, e[i].to)] = c ; 
			cost[mp(e[i].to, e[i].fr)] = - c ; 
		} 
	} 
	void put() {
		for(re int i = 2; i <= cnt; i += 2) {
			if( e[i].fr == 0 || e[i].to == 0 ) continue ; 
			double c = e[i ^ 1].w ; 
			FF[mp(e[i].fr, e[i].to)] = c ; 
			FF[mp(e[i].to, e[i].fr)] = -c ; 
		}
	}
	void init() {
		S = 0, T = 3, cnt = 1, memset( head, 0, sizeof(head) ) ;
	}
} flow[3] ;
signed main()
{
	cin >> n >> m >> K >> alpha ;
	rep( i, 0, 2 ) flow[i].init() ; 
	int x, y ; double z ;
	rep( i, 1, m ) {
		cin >> x >> y >> z, s[i] = (S){x, y, z} ; 
		sf[mp(x, y)] = 1, sf[mp(y, x)] = -1 ; 
		rep( j, 0, 2 ) flow[j].undir(x, y, z) ;
		dw[mp(x, y)] = dw[mp(y, x)] = z ; 
	}
	flow[0].S = 1, flow[1].S = 2, flow[2].S = 0 ;
	flow[2].undir(0, 1, inf), flow[2].undir(0, 2, inf) ;
	double F = flow[0].dinic() ; 
	double W = flow[1].dinic() ;
	double Z = flow[2].dinic() ; 
	double ll = Z - W, rr = F ;
	double ff = max(ll, min(rr, alpha * Z)) ;
	double ans = pow(ff, alpha) * pow(Z - ff, 1 - alpha) ; 
	ans = ans / pow(K, alpha) ; 
	flow[2].init() ; 
	rep( i, 1, m ) 
		x = s[i].x, y = s[i].y, z = s[i].z,
		flow[2].undir(x, y, z) ;
	flow[2].S = 0, flow[2].dir(0, 1, ff), flow[2].dir(0, 2, Z - ff) ;
	flow[2].dinic(), flow[2].build(), flow[2].init() ; 
	rep( i, 1, top ) 
		x = st[i].x, y = st[i].y, z = st[i].z, flow[2].dir(x, y, z) ;
	flow[2].dir(0, 1, ff), flow[2].dinic(), flow[2].put() ; 
	rep( i, 1, m ) {
		x = s[i].x, y = s[i].y ; 
		printf("%.10lf %.10lf\n", FF[mp(x, y)] / K, cost[mp(x, y)] - FF[mp(x, y)] ) ; 
	}
	printf("%.10lf\n", ans ) ; 
	return 0 ;
}
posted @ 2020-10-26 15:56  Soulist  阅读(291)  评论(0编辑  收藏  举报