• Luogu P3305 [SDOI2013]费用流 二分 网络流


    题目链接 (Click) (Here)

    非常有趣的一个题目。

    关键结论:所有的单位费用应该被分配在流量最大的边上。

    即:在保证最大流的前提下,使最大流量最小。这里我们采用二分的方法,每次判断让所有边的流量(<=mid)时是否依然有最大流,求得最小的最大流量(*p)即可。

    为什么会有实数流量呢?其实我也不懂,不过这也造成这个题目需要把流量改成(double),有很多细节需要小心谨慎。。。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 400010;
    const int M = 400010;
    const int INF = 0x3f3f3f3f;
    
    int u[N], v[N], flow[N]; double f[N];
    
    int n, m, p, cnt = -1, head[N];
    
    struct edge {
    	int nxt, to; double f;
    }e[M];
    
    void add_edge (int from, int to, double flw) {
    	e[++cnt].nxt = head[from];
    	e[cnt].to = to;
    	e[cnt].f = flw;
    	head[from] = cnt;
    }
    
    void add_len (int u, int v, double f) {
    	add_edge (u, v, f);
    	add_edge (v, u, 0);
    }
    
    queue <int> q;
    int cur[N], deep[N];
    
    bool bfs (int s, int t) {
    	memcpy (cur, head, sizeof (head));
    	memset (deep, 0x3f, sizeof (deep));
    	deep[s] = 0; q.push (s);
    	while (!q.empty ()) {
    		int u = q.front (); q.pop ();
    		for (int i = head[u]; ~i; i = e[i].nxt) {
    			int v = e[i].to;
    			if (deep[v] == INF && fabs (e[i].f) > 1e-8) {
    				deep[v] = deep[u] + 1;
    				q.push (v);
    			}
    		}
    	}
    	return deep[t] != INF;
    }
    
    double dfs (int u, int t, double lim) {
    	if (u == t || fabs (lim) < 1e-8) {
    		return lim;
    	}
    	double tmp = 0, flow = 0;
    	for (int &i = cur[u]; ~i; i = e[i].nxt) {
    		int v = e[i].to;
    		if (deep[v] == deep[u] + 1) {
    			tmp = dfs (v, t, min (lim, e[i].f));
    			lim -= tmp;
    			flow += tmp;
    			e[i ^ 0].f -= tmp;
    			e[i ^ 1].f += tmp;
    			if (fabs (lim) < 1e-8) break;
    		}
    	}
    	return flow;
    } 
    
    double Dinic (int s, int t) {
    	double res = 0;
    	while (bfs (s, t)) {
    		res += dfs (s, t, INF);
    	}
    	return res;
    }
    
    double max_flow;
    
    bool can_use (double flw) {
    	cnt = -1; int s = 1, t = n;
    	memset (head, -1, sizeof (head));
    	for (int i = 1; i <= m; ++i) {
    		add_len (u[i], v[i], min (f[i], flw));
    	}
    	return fabs (Dinic (s, t) - max_flow) < 1e-8;
    }
    
    int main () {
    	memset (head, -1, sizeof (head));
    	cin >> n >> m >> p;
    	for (int i = 1; i <= m; ++i) {
    		cin >> u[i] >> v[i] >> f[i];
    		add_len (u[i], v[i], f[i]);
    	}
    	int s = 1, t = n; max_flow = Dinic (s, t);
    	printf ("%.0lf
    ", max_flow);
    	double l = 0, r = INF;
    	while (r - l > 1e-8) {
    		double mid = (l + r) / 2.0;
    		if (can_use (mid)) {
    			r = mid;
    		} else {
    			l = mid;
    		}
    	}
    	printf ("%.4lf
    ", r * p);
    } 
    
    
  • 相关阅读:
    Linux下Tomcat服务器-maven项目部署
    数据库设计感悟
    数据库设计规范
    从零到一: 代码调试
    Java泛型与反射的综合应用
    Eclipse中,tomcat插件方式启动项目
    集合查询表--Map
    集合线性表--List之LinkedList(队列与栈)
    集合线性表--List之ArrayList
    Java中的日期操作
  • 原文地址:https://www.cnblogs.com/maomao9173/p/10505926.html
Copyright © 2020-2023  润新知