散落星河的记忆🌠
Published on 2017-09-02 11:31 in 暂未分类 with 散落星河的记忆🌠

[BZOJ 2285] [SDOI 2011] 保密

Description

传送门

Solution

这道题的最大难点在于读懂题意(雾

分数规划求出 \(n\)\(1\cdots n_1\) 每个点的最小 \(\sum\frac{t_i}{s_i}\),然后转换成最小点权覆盖问题,最小点权覆盖 = 最大匹配数。

Code

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>

const double eps = 1e-8, INF = 1e9;
struct Edge1 { int v, nxt; double f, c; } e[80325];
struct Edge2 { int v, nxt, t, s; double w; } g[100005];
int n, m, nn, mm, hd[702], head[165], tot, S, T, cur[165], d[165], cnt;

int read() {
	int x = 0; char c = getchar();
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
	return x;
}
void add(int u, int v, int t, int s) {
	g[++tot].nxt = hd[u], hd[u] = tot, g[tot].v = v, g[tot].t = t, g[tot].s = s;
}
void adde(int u, int v, double c) {
	e[++tot].nxt = head[u], head[u] = tot, e[tot].v = v, e[tot].f = 0, e[tot].c = c;
	e[++tot].nxt = head[v], head[v] = tot, e[tot].v = u, e[tot].f = 0, e[tot].c = 0;
}
bool bfs() {
	bool vis[165] = {}; std::queue<int> q; vis[S] = 1, q.push(S);
	while (!q.empty()) {
		int u = q.front(); q.pop();
		for (int i = head[u]; i; i = e[i].nxt)
			if (!vis[e[i].v] && e[i].c > e[i].f + eps)
				d[e[i].v] = d[u] + 1, vis[e[i].v] = 1, q.push(e[i].v);
	}
	return vis[T];
}
double dfs(int u, double a) {
	if (u == T || a < eps) return a;
	double flow = 0, x;
	for (int &i = cur[u]; i; i = e[i].nxt)
		if (d[u] + 1 == d[e[i].v] && (x = dfs(e[i].v, std::min(a, e[i].c - e[i].f))) > eps) {
			e[i].f += x, e[i ^ 1].f -= x, flow += x, a -= x;
			if (a < eps) break;
		}
	return flow;
}
double dinic() {
	double flow = 0;
	while (bfs()) memcpy(cur, head, sizeof head), flow += dfs(S, INF);
	return flow;
}
bool check(int x, double mid) {
	int d[702] = {}; double f[702] = {}; std::queue<int> q;
	for (int i = 1; i <= m; ++i) g[i].w = g[i].t - mid * g[i].s, ++d[g[i].v];
	for (int i = 1; i <= n; ++i) { if (!d[i]) q.push(i); f[i] = INF; }
	f[n] = 0;
	while (!q.empty()) {
		int u = q.front(); q.pop();
		for (int i = hd[u]; i; i = g[i].nxt) {
			f[g[i].v] = std::min(f[g[i].v], f[u] + g[i].w);
			if (--d[g[i].v] == 0) q.push(g[i].v);
		}
	}
	return f[x] > eps;
}
bool bfs2() {
	int cnt = 0, vis[702] = {}; std::queue<int> q;
	q.push(n), vis[n] = 1, cnt += (n == nn);
	while (!q.empty()) {
		int u = q.front(); q.pop();
		for (int i = hd[u]; i; i = g[i].nxt) if (!vis[e[i].v]) {
			vis[e[i].v] = 1, q.push(e[i].v);
			if ((cnt += (e[i].v <= nn)) == nn) return false;
		}
	}
	return cnt < nn;
}
int main() {
	n = read(), m = read();
	for (int i = 1, u, v, t, s; i <= m; ++i)
		u = read(), v = read(), t = read(), s = read(), add(u, v, t, s);
	tot = 1, mm = read(), nn = read(), S = nn + 1, T = S + 1;
	for (int i = 1, u, v; i <= mm; ++i) u = read(), v = read(), adde(u, v, INF);
	if (bfs2()) { puts("-1"); return 0; }
	for (int i = 1; i <= nn; ++i) {
		double l = 0, r = 10, mid;
		while (l + eps < r) {
			mid = (l + r) / 2;
			if (check(i, mid)) l = mid; else r = mid;
		}
		if (i & 1) adde(S, i, l); else adde(i, T, l);
	}
	printf("%.1lf\n", dinic());
	return 0;
}
posted @ 2019-02-22 17:54  散落星河的记忆🌠  阅读(228)  评论(0编辑  收藏  举报