明显的分数规划,二分一个答案
然后再二分图匹配
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int M=210;queue<int>q;const double INF=20000000.0;
int n,S,T,mflow;bool vis[M];double cos[M*M],mcost,a[M][M],b[M][M],dis[M];
int nex[M*M],head[M],to[M*M],cap[M*M],pre[M],id[M],tot,flow[M];
void add(int x,int y,int z,double w){
nex[++tot]=head[x];
cos[tot]=w;cap[tot]=z;
head[x]=tot;to[tot]=y;
}
int spfa(int s,int t){
memset(vis,0,sizeof vis);memset(pre,-1,sizeof pre);
for(int i=0;i<=2*n+1;i++) dis[i]=INF;
dis[s]=0;q.push(s);vis[s]=1;flow[s]=INF;
while(!q.empty()){
int x=q.front();q.pop(),vis[x]=0;
for(int i=head[x],tmp;i>=2;i=nex[i]){
if(dis[tmp=to[i]]>dis[x]+cos[i]&&cap[i]){
dis[tmp]=dis[x]+cos[i];id[tmp]=i;
pre[tmp]=x;flow[tmp]=min(flow[x],cap[i]);
if(!vis[tmp]) q.push(tmp),vis[tmp]=1;
}
}
}
return dis[t]<INF;
}
bool check(double x){
tot=1;mflow=mcost=0;memset(head,0,sizeof head);
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) add(i,j+n,1,x*b[i][j]-a[i][j]),add(j+n,i,0,a[i][j]-x*b[i][j]);
for(int i=1;i<=n;i++) add(S,i,1,0),add(i,S,0,0),add(i+n,T,1,0),add(T,i+n,0,0);
while(spfa(S,T)){int k=T;
while(k!=S){
cap[id[k]]-=flow[T],cap[id[k]^1]+=flow[T];
k=pre[k];
}
mflow+=flow[T];mcost+=(double)flow[T]*dis[T];
}
return -mcost>=0.0000001;
}
int main(){
scanf("%d",&n);T=2*n+1;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) scanf("%lf",&a[i][j]);
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) scanf("%lf",&b[i][j]);
double l=0,r=1e5;
while(l+0.0000001<=r){double mid=(l+r)/2;
if(check(mid)) l=mid;else r=mid;
}
printf("%lf",l);
}