BZOJ4819 [Sdoi2017]新生舞会 【01分数规划 + 费用流】

题目

学校组织了一次新生舞会,Cathy作为经验丰富的老学姐,负责为同学们安排舞伴。有n个男生和n个女生参加舞会
买一个男生和一个女生一起跳舞,互为舞伴。Cathy收集了这些同学之间的关系,比如两个人之前认识没计算得出
a[i][j] ,表示第i个男生和第j个女生一起跳舞时他们的喜悦程度。Cathy还需要考虑两个人一起跳舞是否方便,
比如身高体重差别会不会太大,计算得出 b[i][j],表示第i个男生和第j个女生一起跳舞时的不协调程度。当然,
还需要考虑很多其他问题。Cathy想先用一个程序通过a[i][j]和b[i][j]求出一种方案,再手动对方案进行微调。C
athy找到你,希望你帮她写那个程序。一个方案中有n对舞伴,假设没对舞伴的喜悦程度分别是a'1,a'2,...,a'n,
假设每对舞伴的不协调程度分别是b'1,b'2,...,b'n。令
C=(a'1+a'2+...+a'n)/(b'1+b'2+...+b'n),Cathy希望C值最大。

输入格式

第一行一个整数n。
接下来n行,每行n个整数,第i行第j个数表示a[i][j]。
接下来n行,每行n个整数,第i行第j个数表示b[i][j]。
1<=n<=100,1<=a[i][j],b[i][j]<=10^4

输出格式

一行一个数,表示C的最大值。四舍五入保留6位小数,选手输出的小数需要与标准输出相等

输入样例

3

19 17 16

25 24 23

35 36 31

9 5 6

3 4 2

7 8 9

输出样例

5.357143

题解

看到比值,01分数规划就很明显了

我们二分答案\(c\),建立二分图,连边\(a_{(i,j)} - c * b_{(i,j)}\)
跑最大费用最大流检验即可

【卡卡常就卡进去了】

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (register int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 205,maxm = 100005,INF = 1000000000;
inline int read(){
	int out = 0,flag = 1; char c = getchar();
	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
	return out * flag;
}
int h[maxn],ne = 2;
struct EDGE{int to,nxt,f; double w;}ed[maxm];
inline void build(int u,int v,int f,double w){
	ed[ne] = (EDGE){v,h[u],f,w}; h[u] = ne++;
	ed[ne] = (EDGE){u,h[v],0,-w}; h[v] = ne++;
}
int n,S,T,head,tail,q[maxm];
int a[maxn][maxn],b[maxn][maxn];
double d[maxn];
int minf[maxn],p[maxn],inq[maxn];
inline double maxcost(){
	int u; double cost = 0;
	while (true){
		for (int i = S; i <= T; i++) d[i] = -INF,inq[i] = minf[i] = 0;
		q[head = tail = 1] = S; minf[S] = INF; d[S] = 0;
		while (head <= tail){
			u = q[head++];
			inq[u] = false;
			Redge(u) if (ed[k].f && d[to = ed[k].to] < d[u] + ed[k].w){
				d[to] = d[u] + ed[k].w; p[to] = k;
				minf[to] = min(minf[u],ed[k].f);
				if (!inq[to]) q[++tail] = to,inq[to] = true;
			}
		}
		if (!minf[T]) return cost;
		cost += minf[T] * d[T];
		u = T;
		while (u != S){
			ed[p[u]].f -= minf[T];
			ed[p[u] ^ 1].f += minf[T];
			u = ed[p[u] ^ 1].to;
		}
	}
}
bool check(double c){
	ne = 2; memset(h,0,sizeof(h));
	REP(i,n) build(S,i,1,0),build(n + i,T,1,0);
	REP(i,n) REP(j,n) build(i,n + j,1,a[i][j] - c * b[i][j]);
	return maxcost() >= 0;
}
int main(){
	n = read(); S = 0; T = n << 1 | 1;
	REP(i,n) REP(j,n) a[i][j] = read();
	REP(i,n) REP(j,n) b[i][j] = read();
	double l = 0,r = 100000,mid;
	while (r - l >= 1e-7){
		mid = (l + r) / 2;
		if (check(mid)) l = mid;
		else r = mid;
	}
	printf("%.6lf\n",(l + r) / 2);
	return 0;
}

posted @ 2018-04-19 19:56  Mychael  阅读(138)  评论(0编辑  收藏  举报