【BZOJ4819】新生舞會(分數規劃,網絡流)
阿新 • • 發佈:2018-05-25
保留 要求 fin rip set 現在 分數規劃 方便 cstring
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值最大。
【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
假設每對舞伴的不協調程度分別是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】新生舞會(分數規劃,網絡流)