zoj 2676 Network Wars(01分数规划+最大流)

给一个无向有权图, 选定一个边集, 使得平均边权最小。


先二分平均边权, 假设为x,构建新图,边权为原来边权减去x,如果边权小于0的话就是一定要选的, 所以可以不加入新图, 然后在新图上跑最大流, 求出最小割。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;

#define LL long long
#define inf 0x3f3f3f3f
#define mnx 102
#define mxe 2020
#define eps 1e-5
#define ls (i << 1)
#define rs (ls | 1)
#define md ((ll + rr) >> 1)

int n, m;
int from[mxe], To[mxe], val[mxe];
bool sel[mxe];

int dcmp(double x) {
	if(fabs(x) <= eps) return 0;
	return x < 0? -1: 1;
}
struct dinic {
	int fst[mnx], nxt[mxe], to[mxe], e;
	int s, t;
	double cap[mxe], flow[mxe];
	int d[mnx], cur[mnx];
	bool vis[mnx];
	vector<int> ans;

	void init() {
		memset(fst, -1, sizeof fst);
		e = 0;
	}
	void add(int u, int v, double c) {
		to[e] = v, nxt[e] = fst[u], cap[e] = c, flow[e] = 0, fst[u] = e++;
		to[e] = u, nxt[e] = fst[v], cap[e] = 0, flow[e] = 0, fst[v] = e++;
	}
	bool bfs(bool flag = 0) {
		memset(d, 0x3f, sizeof d);
		queue<int> q;
		q.push(s);
		d[s] = 0;
		while(!q.empty()) {
			int u = q.front(); q.pop();
			if(flag) vis[u] = 1;
			for(int i = fst[u]; ~i; i = nxt[i]) {
				int v = to[i];
				if(dcmp(cap[i] - flow[i]) > 0 && d[v] == inf) {
					d[v] = d[u] + 1;
					q.push(v);
				}
			}
		}
		return d[t] != inf;
	}
	double dfs(int x, double a) {
		if(x == t || dcmp(a) <= 0) return a;
		double f, ret = 0;
		for(int &i = cur[x]; ~i; i = nxt[i]) {
			int v = to[i];
			if(d[v] == d[x] + 1 && dcmp(f = dfs(v, min(a, cap[i] - flow[i]))) > 0) {
				a -= f;
				flow[i] += f;
				flow[i ^ 1] -= f;
				ret += f;
				if(dcmp(a) <= 0) break;
			}
		}
		return ret;
	}
	double go(int s, int t) {
		this -> s = s, this -> t = t;
		double ret = 0;
		while(bfs()) {
			for(int i = 1; i <= n; ++i) cur[i] = fst[i];
			ret += dfs(s, inf);
		}
		return ret;
	}
	void getAns() {
		memset(vis, 0, sizeof vis);
		bfs(1);
		for(int i = 1; i <= m; ++i) {
			int u = from[i], v = To[i];
			if(vis[u] ^ vis[v] == 1 && !sel[i])
				ans.push_back(i);
		}
		sort(ans.begin(), ans.end());
		printf("%d\n", ans.size());
		for(int i = 0; i < ans.size(); ++i)
			printf("%d%c", ans[i], i == ans.size() - 1? '\n': ' ');
	}

}go;

bool check(double x, bool flag = 0) {
	go.init();
	double res = 0;
	for(int i = 1; i <= m; ++i) {
		if(dcmp(val[i] - x) <= 0) {
			res += val[i] - x;
			if(flag) {
				go.ans.push_back(i);
				sel[i] = 1;
			}
		}
		else
			go.add(from[i], To[i], val[i] - x),
			go.add(To[i], from[i], val[i] - x);
	}
	res += go.go(1, n);
	return res > 0;
}
int main() {
	while(scanf("%d%d", &n, &m) != EOF) {
		for(int i = 1; i <= m; ++i) {
			scanf("%d%d%d", &from[i], &To[i], &val[i]);
		}
		memset(sel, 0, sizeof sel);
		double l = 0, r = 1e8;
		while(r - l > 1e-8) {
			double mid = (l + r) / 2;
			if(check(mid))
				l = mid;
			else
				r = mid;
		}
		go.ans.clear();
		check(l, 1);
		go.getAns();
	}
	return 0;
}


你可能感兴趣的:(最大流,01分数规划)