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\n", 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\n", r * p);
} 

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号