首先是题目链接:
luogu:https://www.luogu.com.cn/problem/P3705
loj:https://loj.ac/problem/2003
bzoj:http://www.lydsy.com/JudgeOnline/problem.php?id=4819
发现题目要求 最大化
稍作变形得
于是容易想到二分答案,并将第个男生和第个女生连一条权值为的边,用KM算法进行带权二分图最大匹配。
如果匹配结果大于等于,则答案小于等于
代码:
#include<bits/stdc++.h> #define rep(i,a,b) for(register int i=a;i<=b;++i) #define N 110 #define INF 1000000007 inline int read() { bool f=0;int x=0;char ch; do{ch=getchar();f|=(ch=='-');}while(!isdigit(ch)); do{x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}while(isdigit(ch)); return f?-x:x; } using namespace std; int n,a[N][N],b[N][N],match[N]; double lx[N],ly[N],val[N][N]; bool vx[N],vy[N]; bool dfs(int x) { vx[x]=1; rep(y,1,n) if(!vy[y]&&lx[x]+ly[y]-val[x][y]==0) { vy[y]=1; if(match[y]==-1||dfs(match[y])) { match[y]=x; return 1; } } return 0; } inline bool KM() { memset(ly,0.0,sizeof(ly)); rep(i,1,n) { lx[i]=-INF; rep(j,1,n)lx[i]=max(lx[i],val[i][j]); } memset(match,-1,sizeof(match)); rep(i,1,n) while(1) { memset(vx,0,sizeof(vx)); memset(vy,0,sizeof(vy)); if(dfs(i)) break; double d=INF; rep(x,1,n)if(vx[x]) rep(y,1,n)if(!vy[y]) d=min(d,lx[x]+ly[y]-val[x][y]); if(d==INF) return -1; rep(x,1,n) if(vx[x]) lx[x]-=d; rep(y,1,n) if(vy[y]) ly[y]+=d; } double res=0; rep(i,1,n) if(match[i]>-1) res+=val[match[i]][i]; return res>0; } int main() { n=read(); rep(i,1,n)rep(j,1,n) a[i][j]=read(); rep(i,1,n)rep(j,1,n) b[i][j]=read(); double l=0,r=1e4,mid; while(r-l>=1e-8) { mid=l+(r-l)/2; rep(i,1,n)rep(j,1,n)val[i][j]=1.0*a[i][j]-mid*b[i][j]; if(KM()) l=mid; else r=mid; } printf("%.6lf",mid); return 0; }