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
19 17 16
25 24 23
35 36 31
9 5 6
3 4 2
7 8 9
Sample Output
5.357143
二分答案mid
然后把每个匹配权值变成a[i][j]-mid*b[i][j](最优比例生成树的套路)
然后求出最大权值匹配
没有用KM算法,直接建网络流模型,权值取负,跑最小费用流
看最小费用是否小于0
此题卡常,不用结构体快1倍
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
int from[],next[],to[],cap[];
double dis[];
int num=,head[],path[],n;
double dist[],a[][],b[][];
bool vis[];
void add(int u,int v,int c,double d)
{
num++;
next[num]=head[u];
head[u]=num;
to[num]=v;
from[num]=u;
cap[num]=c;
dis[num]=d;
}
bool SPFA(int S,int T)
{int i;
queue<int>Q;
memset(vis,,sizeof(vis));
memset(path,-,sizeof(path));
for (i=S;i<=T;i++)
dist[i]=1e9;
Q.push(S);
dist[S]=;
while (Q.empty()==)
{
int u=Q.front();
Q.pop();
vis[u]=;
for (i=head[u];i!=-;i=next[i])
if (cap[i])
{
int v=to[i];
if (dist[v]>dist[u]+dis[i])
{
dist[v]=dist[u]+dis[i];
path[v]=i;
if (vis[v]==)
{
vis[v]=;
Q.push(v);
}
}
}
}
if (dist[T]==1e9) return ;
return ;
}
double mincost(int S,int T)
{int i;
double ans=;
while (SPFA(S,T))
{
for (i=path[T];i!=-;i=path[from[i]])
{
cap[i]-=;
cap[i^]+=;
}
ans+=dist[T];
}
return ans;
}
bool check(double mid)
{int S,T,i,j;
double ans;
memset(head,-,sizeof(head));
num=;S=;T=*n+;
for (i=;i<=n;i++)
{
add(S,i,,);add(i,S,,);
add(n+i,T,,);add(T,n+i,,);
}
for (i=;i<=n;i++)
{
for (j=;j<=n;j++)
{
double res=a[i][j]-mid*b[i][j];
add(i,n+j,,-res);add(n+j,i,,res);
}
}
ans=mincost(S,T);
if (ans<) return ;
return ;
}
int main()
{int i,j;
cin>>n;
for (i=;i<=n;i++)
{
for (j=;j<=n;j++)
{
scanf("%lf",&a[i][j]);
}
}
for (i=;i<=n;i++)
{
for (j=;j<=n;j++)
{
scanf("%lf",&b[i][j]);
}
}
double l=,r=;
while (r-l>1e-)
{
double mid=(l+r)/2.0;
if (check(mid)) l=mid;
else r=mid;
}
printf("%.6lf\n",(l+r)/2.0);
}