[ SDOI 2017 ] 新生舞会

题目

Luogu
LOJ
Acwing

思路

[ SDOI 2017 ] 新生舞会
[ SDOI 2017 ] 新生舞会

[ SDOI 2017 ] 新生舞会

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 410, M = 500010;
const double eps = 1e-7;
int n, m, S, T, b[N][N], a[N][N];
// 前向星
int h[N], ptr[M], val[M], f[M], idx;
// 边权
double w[M];
void add(int a, int b, int c, double d) { val[idx] = b, w[idx] = d, f[idx] = c, ptr[idx] = h[a], h[a] = idx++; }
void add(int a, int b, int c, int d, double e) { add(a, b, c, e), add(b, a, d, -e); }
double d[N];
int incf[N], q[N], st[N], pre[N];
bool SPFA() {
	int hh = 0, tt = 0;
	for (int i = 0; i <= n * 2 + 1; i++) d[i] = -2e9;
	memset(incf, 0, sizeof incf), memset(st, 0, sizeof st);
	memset(pre, -1, sizeof pre);
	d[S] = 0, q[tt++] = S, st[S] = true, incf[S] = 2e9;
	for (int t = q[hh]; hh++ != tt; t = q[hh]) {
		if (hh == N - 1) hh = 0;
		st[t] = false;
		for (int i = h[t], v = val[i]; i != -1; i = ptr[i], v = val[i])
			if (f[i] && d[v] < d[t] + w[i]) {
				d[v] = d[t] + w[i], pre[v] = i;
				incf[v] = min(incf[t], f[i]);
				if (st[v]) continue;
				q[tt++] = v, st[v] = true;
				if (tt == N - 1) tt = 0;
			}
	}
	return incf[T] > 0;
}
double EK() {
    int res = 0;
	double cost = 0;
	while (SPFA()) {
		int t = incf[T];		
		res += t, cost += t * d[T];
		for (int i = T; i != S; i = val[pre[i] ^ 1]) 
            f[pre[i]] -= t, f[pre[i] ^ 1] += t;
	}
	return cost;
}
bool check(double mid) {
    // 连边
	memset(h, -1, sizeof h), idx = 0;
	// 源点到男生
	for (int i = 1; i <= n; i++) add(S, i, 1, 0, 0);
	// 女生到汇点
	for (int i = 1; i <= n; i++) add(i + n, T, 1, 0, 0);
	// 男女之间连边
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			add(i, j + n, 1, 0, a[i][j] - mid * b[i][j]);
	// 费用流
	return EK() >= 0; 
}
int main() {
	cin >> n;
	S = 0, T = 2 * n + 1;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			cin >> a[i][j];
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			cin >> b[i][j];
	// 二分答案
	double l = 0, r = 1e4;
	while (r - l > eps) {
		double mid = (l + r) / 2;
		if (check(mid)) l = mid;
		else r = mid;
	}
	printf("%.6lf", r);
	return 0;
}
上一篇:STL标准模板库


下一篇:[ SDOI 2016 ] 储能表