题面
https://www.lydsy.com/JudgeOnline/problem.php?id=4819
题解
这题很好想 首先二分答案 然后令w[i][j]=a[i][j]-b[i][j]*nwans
那么只要判断能否找出一个完美匹配 使得
KM算法或者费用流都可以做
Code
KM算法
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 ll read(){ 6 ll x=0,f=1;char c=getchar(); 7 while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();} 8 while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();} 9 return x*f; 10 } 11 12 const int maxn=110; 13 double w[maxn][maxn]; //边权 14 double la[maxn],lb[maxn]; //左右点的顶标 15 bool va[maxn],vb[maxn]; //访问标记(是否在交错树中) 16 int match[maxn]; //右部点匹配了哪一个左部点 17 int n; 18 double delta; 19 20 bool dfs(int x){ 21 va[x]=1; 22 for(int y=1;y<=n;y++) 23 if(!vb[y]) 24 if(fabs(la[x]+lb[y]-w[x][y])<=1e-8){ //相等子图 25 vb[y]=1; 26 if(!match[y] || dfs(match[y])){ 27 match[y]=x; 28 return 1; 29 } 30 } 31 else delta=min(delta,la[x]+lb[y]-w[x][y]); 32 return 0; 33 } 34 35 double KM(){ 36 memset(match,0,sizeof(match)); 37 for(int i=1;i<=n;i++){ 38 la[i]=-(1<<30); 39 lb[i]=0; 40 for(int j=1;j<=n;j++) 41 la[i]=max(la[i],w[i][j]); 42 } 43 for(int i=1;i<=n;i++) 44 while(1){ 45 memset(va,0,sizeof(va)); 46 memset(vb,0,sizeof(vb)); 47 delta=1<<30; 48 if(dfs(i)) break; 49 for(int j=1;j<=n;j++){ 50 if(va[j]) la[j]-=delta; 51 if(vb[j]) lb[j]+=delta; 52 } 53 } 54 double ans=0; 55 for(int i=1;i<=n;i++) 56 ans+=w[match[i]][i]; 57 return ans; 58 } 59 60 int a[maxn][maxn],b[maxn][maxn]; 61 62 int main(){ 63 #ifdef LZT 64 freopen("in","r",stdin); 65 #endif 66 67 n=read(); 68 for(int i=1;i<=n;i++) 69 for(int j=1;j<=n;j++) 70 a[i][j]=read(); 71 for(int i=1;i<=n;i++) 72 for(int j=1;j<=n;j++) 73 b[i][j]=read(); 74 double l=0,r=1e4; 75 while(r-l>(1e-8)){ 76 double md=(l+r)/2; 77 for(int i=1;i<=n;i++) 78 for(int j=1;j<=n;j++) 79 w[i][j]=a[i][j]-b[i][j]*md; 80 if(KM()>=0) l=md; 81 else r=md; 82 // cout<<l<<' '<<r<<endl; 83 } 84 printf("%.6f\n",l); 85 return 0; 86 }
费用流