• 【codeforces



    description

    给定 n 点 m 边简单有向图,有边权。

    q 次询问,每次给出 xi。可以增加某些边的边权,要求总增加量小于等于 xi,最大化点 1 到点 n 的最短路。

    原题链接。

    solution

    可以去看看dls表演如何正确切这道题:读完题发现是原题,找题解读了一遍,过了。

    设答案的下界为 (D),边权增长量为 (a_{u, v}),最短路为 (d_i)
    可以根据最短路的三角不等式列出如下线性规划式:

    [min{sum_{(u,v)in E}a_{u,v}} \ egin{cases} d_u - d_v+a_{u, v}geq -w_{u,v} \ d_n - d_1geq D \ d_igeq 0, a_{u,v} geq 0 end{cases} ]

    如果目标函数 (leq x_i),则 (D) 是一个合法的下界。

    考虑它的对偶问题:

    [max{D imes f-sum_{(u,v)in E}w_{u,v} imes b_{u,v}} \ egin{cases} sum_{i}b_{u,i}-sum_{i}b_{i,u}leq 0 & u ot=1,n \ sum_{i}b_{1,i}-sum_{i}b_{i,1}-fleq 0 \ sum_{i}b_{n,i}-sum_{i}b_{i,n}+fleq 0 \ 0leq b_{u,v}leq 1,0leq f end{cases} ]

    注意到这个约束条件长得很像 “流量守恒” + “容量限制”。
    事实上,这就是网络流的线性规划式(引用 freopen 的一句话:在一个图中,每个点入度 ≤ 出度即可构成入度 = 出度)。其中 (1) 为源点,(n) 为汇点,(f) 为整个网络的流量。

    (c = sum w_{u,v} imes b_{u,v}),则已知 (f) 时我们需要最小化 (c)。跑最小费用流即可。

    由于 (D imes f-cleq x_i),可以得到 (Dleqfrac{x_i+c}{f})
    注意到二元组 ((f,c)) 只有 (O(n)) 个,每次增广单位流量可以找到所有的二元组。

    于是可以 (O(n)) 处理一次询问(也可以处理出凸包 + 二分 (O(log)) 处理一次询问)。


    还有另一种转化问题的方法:

    一样地设下界为 (D),边权增长量为 (a_i)。考虑 1 -> n 的所有路径 (L_p),有线性规划式:

    [min{sum_{(u,v)in E}a_{u,v}leq x_i} \ egin{cases} sum_{(u,v)in L_p}(w_{u,v}+a_{u,v})geq D\ a_{u,v}geq 0 end{cases} ]

    对偶:

    [max{sum_{p}y_p imes(D - sum_{(u,v)in L_p} w_{u,v})} \ egin{cases} sum y_p leq 1 & (u, v)in L_p \ y_p geq 0 end{cases} ]

    可以看成选 (k) 条路径,每条边只能被一条路径经过,最小化 (sum_{p}y_p imessum_{(u,v)in L_p} w_{u,v})
    这一步以后的过程就和上面的推导是一样的。

    accepted code

    #include <queue>
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    typedef pair<int, int> pii;
    #define pr make_pair
    #define fi first
    #define se second
    
    namespace fgraph{
    	const int MAXV = 50;
    	const int MAXE = 10*MAXV*MAXV;
    	const int INF = (1 << 30);
    	
    	struct edge{
    		int to, cap, flow, cost;
    		edge *nxt, *rev;
    	}edges[MAXE + 5], *adj[MAXV + 5], *cur[MAXV + 5], *ecnt = edges;
    	void addedge(int u, int v, int c, int w) {
    		edge *p = (++ecnt), *q = (++ecnt);
    		(*p) = (edge){v, c, 0, w, adj[u], q}, adj[u] = p;
    		(*q) = (edge){u, 0, 0, -w, adj[v], p}, adj[v] = q;
    	}
    	int d[MAXV + 5], h[MAXV + 5], s, t;
    	bool relabel() {
    		for(int i=s;i<=t;i++)
    			h[i] += d[i], d[i] = INF, cur[i] = adj[i];
    		priority_queue<pii, vector<pii>, greater<pii> >que;
    		que.push(pr(d[t] = 0, t));
    		while( !que.empty() ) {
    			int k = que.top().fi, x = que.top().se; que.pop();
    			if( k != d[x] ) continue;
    			for(edge *p=adj[x];p;p=p->nxt) {
    				if( p->rev->cap > p->rev->flow ) {
    					int dis = k + p->rev->cost + (h[x] - h[p->to]);
    					if( dis < d[p->to] ) que.push(pr(d[p->to] = dis, p->to));
    				}
    			}
    		}
    		return d[s] != INF;
    	}
    	bool vis[MAXV + 5];
    	int aug(int x, int tot) {
    		if( x == t ) return tot;
    		vis[x] = true; int sum = 0;
    		for(edge *&p=cur[x];p;p=p->nxt) {
    			int dis = d[p->to] + p->cost + (h[p->to] - h[x]);
    			if( d[x] == dis && !vis[p->to] && p->cap > p->flow ) {
    				int del = aug(p->to, min(tot - sum, p->cap - p->flow));
    				sum += del, p->flow += del, p->rev->flow -= del;
    				if( sum == tot ) break;
    			}
    		}
    		vis[x] = false; return sum;
    	}
    }
    
    int f[55];
    int main() {
    	int n, m; scanf("%d%d", &n, &m);
    	for(int i=1;i<=m;i++) {
    		int u, v, w; scanf("%d%d%d", &u, &v, &w);
    		fgraph::addedge(u, v, 1, w);
    	}
    	int cnt = 0;
    	fgraph::s = 1, fgraph::t = n;
    	for(cnt = 0;fgraph::relabel();cnt++)
    		f[cnt + 1] = f[cnt] + fgraph::d[1] + fgraph::h[1], fgraph::aug(1, 1);
    	
    	int q; scanf("%d", &q);
    	for(int i=1;i<=q;i++) {
    		int x; scanf("%d", &x);
    		
    		double ans = 1E12;
    		for(int j=1;j<=cnt;j++)
    			ans = min(ans, 1.0*(x + f[j])/j);
    		
    		printf("%.9f
    ", ans);
    	}
    }
    

    details

    有如下形式的线性规划式,一般都可以对偶成费用流(据说叫作 LP 对偶费用流),如loj6511「雅礼集训 2018 Day8」B

    [min{sum_{(u,v)in E}c_{u,v} imes x_{u,v}} \ egin{cases} phi_u - phi_v+x_{u, v}geq w_{u,v} \ phi_igeq 0, x_{u,v} geq 0 end{cases} ]

  • 相关阅读:
    js面试题-----算法类
    js面试题-----安全类
    js面试题-----通信类
    js面试题-----面向对象类
    js面试题-----HTTP协议类
    js面试题-----CSS盒模型
    Java-JVM 类的初始化
    加密的相关基础
    AngularJS-directive.js 基本指令
    AngularJS-liveRoomDirective.js 直播间指令
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/13154586.html
Copyright © 2020-2023  润新知