[SDOI2017]新生舞會,洛谷P3705,分數規劃+二分圖最優匹配
阿新 • • 發佈:2018-11-09
正題
題目連結點這裡
給出兩個矩陣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); }