1. 程式人生 > >【BZOJ4819】新生舞會(分數規劃,網絡流)

【BZOJ4819】新生舞會(分數規劃,網絡流)

保留 要求 fin rip set 現在 分數規劃 方便 cstring

【BZOJ4819】新生舞會(分數規劃,網絡流)

題面

BZOJ

Description

學校組織了一次新生舞會,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值最大。

Input

第一行一個整數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

Output

一行一個數,表示C的最大值。四舍五入保留6位小數,選手輸出的小數需要與標準輸出相等

Sample Input

3

19 17 16

25 24 23

35 36 31

9 5 6

3 4 2

7 8 9

Sample Output

5.357143

題解

很明顯的分數規劃了
二分一個答案
現在要讓\(\sum a-mid·\sum b\geq 0\)
顯然是要求二分圖的最大帶權匹配
\(KM\)算法早就不會了
直接上費用流就行了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set> #include<map> #include<vector> #include<queue> using namespace std; #define ll long long #define RG register #define MAX 111 inline int read() { RG int x=0,t=1;RG char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } struct Line{int v,next,w;double fy;}e[MAX*MAX*2]; int h[MAX<<1],cnt; inline void Add(int u,int v,int w,double fy) { e[cnt]=(Line){v,h[u],w,fy};h[u]=cnt++; e[cnt]=(Line){u,h[v],0,-fy};h[v]=cnt++; } double dis[MAX<<1],Cost; bool vis[MAX<<1]; int n,S,T,pe[MAX<<1],pv[MAX<<1]; int a[MAX][MAX],b[MAX][MAX]; bool SPFA() { queue<int> Q;Q.push(S); for(int i=S;i<=T;++i)dis[i]=-1e18; dis[S]=0;vis[S]=true; while(!Q.empty()) { int u=Q.front();Q.pop(); for(int i=h[u];i;i=e[i].next) { int v=e[i].v; if(e[i].w&&dis[v]<dis[u]+e[i].fy) { dis[v]=dis[u]+e[i].fy; pe[v]=i;pv[v]=u; if(!vis[v])vis[v]=true,Q.push(v); } } vis[u]=false; } if(dis[T]<=-1e18)return false; for(int i=T;i!=S;i=pv[i])e[pe[i]].w--,e[pe[i]^1].w++; Cost+=dis[T]; return true; } void Build(double mid) { for(int i=S;i<=T;++i)h[i]=0;cnt=2; for(int i=1;i<=n;++i)Add(S,i,1,0); for(int i=1;i<=n;++i)Add(i+n,T,1,0); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) Add(i,j+n,1,1.0*a[i][j]-mid*b[i][j]); Cost=0; } bool check(double mid) { Build(mid); while(SPFA()); return Cost>=0; } int main() { n=read();S=0;T=n+n+1; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j)a[i][j]=read(); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j)b[i][j]=read(); double l=0,r=1e4; while(r-l>1e-7) { double mid=(l+r)/2; if(check(mid))l=mid; else r=mid; } printf("%.6lf\n",l); return 0; }

【BZOJ4819】新生舞會(分數規劃,網絡流)