zoukankan      html  css  js  c++  java
  • 集训队作业 2021 #114. Son of Pipe Stream

    ( m Son ~of ~Pipe~ Stream(DJ))

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

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

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

    • (vcdot f_i+w_ile c_i)

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

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

    (nle 300,mle 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'=vcdot f_i),限制等价于 (f_i'+w_ile 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 imes (F_{max},S-F_{max})+(1-alpha) imes (S-W_{max}, W_{max})),然后得到答案。

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

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

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

    然后由于 (S) 确定,答案相当于 ((F+W)=S,F^aW^{1-a}) 的最大值,取在 (F'=acdot 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
    ", FF[mp(x, y)] / K, cost[mp(x, y)] - FF[mp(x, y)] ) ; 
    	}
    	printf("%.10lf
    ", ans ) ; 
    	return 0 ;
    }
    
  • 相关阅读:
    服务器的小程序,可以通过浏览器访问该服务器自定义的内容
    GUI小程序---理解GUI
    迷你MyBank
    使用Scanner输入数据-读取文本数据
    文件拷贝代码模型
    File文件操作类
    链表
    ThreadLocal类使用理解
    二叉树
    比较器比较对象数组Comparable和Comparator区别
  • 原文地址:https://www.cnblogs.com/Soulist/p/13878921.html
Copyright © 2011-2022 走看看