正题
题目链接点这里
给出两个矩阵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);
}
本文探讨了如何通过二分图带权匹配算法解决特定矩阵排列问题,使用C++实现了一个基于Kuhn-Munkres算法的解决方案,通过二分查找优化最大权匹配。
604

被折叠的 条评论
为什么被折叠?



