版权声明:因为我是蒟蒻,所以请大佬和神犇们不要转载(有坑)的文章,并指出问题,谢谢 https://blog.csdn.net/Deep_Kevin/article/details/83755924
正题
题目链接点这里
给出两个矩阵a,b,都表示i和j之间的权值,要求构造一个排列P,使得最大。
我们来二分一个mid,使得,然后变形金刚,
那么我们就构造一个排列P使得?
发现是一个二分图带权匹配,因为相当于从i到j建一条权为的边。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int n;
int a[110][110],b[110][110];
double g[110][110];
double tx[110],ty[110];
int prep[110];
bool visx[110],visy[110];
bool find(int x){
visx[x]=true;
for(int i=1;i<=n;i++)
if(tx[x]+ty[i]==g[x][i] && !visy[i]){
visy[i]=true;
if(prep[i]==0 || find(prep[i])){
prep[i]=x;
return true;
}
}
return false;
}
double KM(){
memset(tx,0,sizeof(tx));
memset(ty,0,sizeof(ty));
memset(prep,0,sizeof(prep));
double mmin=1e9;
for(int i=1;i<=n;i++){
while(1){
memset(visx,false,sizeof(visx));
memset(visy,false,sizeof(visy));
if(find(i)) break;
mmin=1e9;
for(int j=1;j<=n;j++) if(visx[j])
for(int k=1;k<=n;k++) if(!visy[k]) mmin=min(mmin,tx[j]+ty[k]-g[j][k]);
for(int j=1;j<=n;j++) if(visx[j]) tx[j]-=mmin;
for(int j=1;j<=n;j++) if(visy[j]) ty[j]+=mmin;
}
}
double ans=0;
for(int i=1;i<=n;i++) ans+=g[prep[i]][i];
return ans;
}
bool check(double x){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
g[i][j]=a[i][j]-b[i][j]*x;
return KM()>=0;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&b[i][j]);
double l=0,r=1e4;
while(r-l>=1e-7){
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
printf("%lf",l);
}