HDU 5988 费用流 16青岛银牌题?

费用不再是相加,而是以概率形式出现,需要相乘
取对数可以将乘法变为加法
然后就是裸的费用流了

注意精度问题,不然会T。。。


#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <iostream>
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long LL;
typedef pair<double, int> P;

const int maxv = 1e2 + 10;

int V;

struct edge {
	int to, cap, rev;
	double cost;
	edge(int to, int cap, double cost, int rev) : to(to), cap(cap), cost(cost), rev(rev) {}
};
double h[maxv];
double dist[maxv];
int prevv[maxv], preve[maxv];

vector<edge> G[maxv];

void add_edge(int from, int to, int cap, double cost) {
	G[from].push_back(edge(to, cap, cost, G[to].size()));
	G[to].push_back(edge(from, 0, -cost, G[from].size() - 1));
}

double min_cost_flow(int s, int t, int f) {
	double res = 0;
	for (int i = 0; i <=V; i++) h[i] = 0;
	while (f > 0) {
		priority_queue<P, vector<P>, greater<P> > que;
		for (int i = 0; i < V; i++) dist[i] = 1e18;
		dist[s] = 0;
		que.push(P(0, s));
		while (!que.empty()) {
			P p = que.top(); que.pop();
			int v = p.second;
			if (dist[v] < p.first) continue;
			for (int i = 0; i < G[v].size(); i++) {
				edge &e = G[v][i];
				if (e.cap > 0 && dist[e.to] - dist[v] - e.cost - h[v] + h[e.to] > eps) {
					dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
					prevv[e.to] = v;
					preve[e.to] = i;
					que.push(P(dist[e.to], e.to));
				}
			}
		}
		for (int v = 0; v < V; v++) h[v] += dist[v];

		int d = f;
		for (int v = t; v != s; v = prevv[v]) {
			d = min(d, G[prevv[v]][preve[v]].cap);
		}
		res += d * h[t];
		f -= d;
		for (int v = t; v != s; v = prevv[v]) {
			edge &e = G[prevv[v]][preve[v]];
			e.cap -= d;
			G[v][e.rev].cap += d;
		}
	}
	return res;
}

int main() {
	int Te; scanf("%d", &Te);
	while (Te--) {
		int f = 0;
		int N, M;
		int S, T;
		scanf("%d%d", &N, &M);
		S = 0; T = N + 1; V = T + 1; for (int i = 0; i < V; i++) G[i].clear();
		int u, v, c;
		double p;
		for (int i = 1; i <= N; i++) {
			scanf("%d%d", &u, &v);
			if (u > v) {
				f += (u - v);
				add_edge(S, i, u - v, 0);
			} else if (u < v) {
				add_edge(i, T, v - u, 0);
			}
		}	
		for (int i = 0; i < M; i++) {
			scanf("%d%d%d%lf", &u, &v, &c, &p);
			p = -log2(1 - p);
			if (c > 0) {
				add_edge(u, v, 1, 0);
				add_edge(u, v, c - 1, p);
			}
		}
		double ans = min_cost_flow(S, T, f);
		printf("%.2lf\n", 1.000 - pow(2, -ans));
	}
	return 0;
}
posted @ 2018-09-19 21:39  xFANx  阅读(141)  评论(0编辑  收藏  举报