发现如果说能够得到一个答案C的话,比这个C小的值都可以不考虑了。因为这个C比较难求,而且n=100,可以直观感觉到这题应该效率可以乱搞,而且多半是复杂度玄学的流之类的。所以就二分答案检查答案合法性。对式子进行一波化简得到了
b1C+b2C+…+bnC=a’1+a’2+…+a’n。
进而
a1-b1C+a2-b2C+….+anC=0
那么如果说得到的值>=0的话说明可以得到更大的C值。
二分C,将每个点连出去的边更正为a-bC的形式走最大费用流(一个典型的用流来确定未确定的边方向的思想)。
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
using namespace std;
int n,nn,m;
inline int read()
{
char c;
bool flag=false;
while((c=getchar())>'9'||c<'0')
if(c=='-')flag=true;
int res=c-'0';
while((c=getchar())>='0'&&c<='9')
res=(res<<3)+(res<<1)+c-'0';
return flag?-res:res;
}
const int N=310;
const int M=50000;
int tot=1,S,T,SS;
double ans;
int nex[M],fir[N],go[M];
int a[N][N],b[N][N],q[1000000],pre[N],prd[N],liu[M],liu_n[N];
double val[M],val_n[N];
bool vis[N];
inline void add(int x,int y,int z,double v)
{
nex[++tot]=fir[x];fir[x]=tot;go[tot]=y;liu[tot]=z;val[tot]=v;
nex[++tot]=fir[y];fir[y]=tot;go[tot]=x;liu[tot]=0;val[tot]=-v;
}
inline void back()
{
int u=T;
while(u)
{
liu[pre[u]]-=liu_n[T];
liu[pre[u]^1]+=liu_n[T];
u=prd[u];
}
ans+=(double)liu_n[T]*val_n[T];
}
inline bool spfa()
{
int t=0,w,u,v,e;
q[w=1]=SS;
for(int i=0;i<=nn;++i) val_n[i]=-1e9;
val_n[SS]=0;
memset(vis,0,sizeof(vis));
liu_n[SS]=1e9;
liu_n[T]=0;
vis[SS]=1;
while(t<w)
{
u=q[++t];
for(e=fir[u];v=go[e],e;e=nex[e])
if(val_n[u]+val[e]>val_n[v]&&liu[e])
{
val_n[v]=val_n[u]+val[e];
liu_n[v]=min(liu_n[u],liu[e]);
pre[v]=e;
prd[v]=u;
if(!vis[v]) q[++w]=v,vis[v]=1;
}
vis[u]=0;
}
return val_n[T]!=val_n[nn];
}
inline bool check(double x)
{
tot=1;
ans=0;
memset(fir,0,sizeof(fir));
add(SS,S,n,0);
for(int i=1;i<=n;++i) add(S,i,1,0),add(i+n,T,1,0);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
add(i,j+n,1,a[i][j]-b[i][j]*x);
while(spfa())
back();
return ans>=0;
}
int main()
{
// freopen("4819.txt","r",stdin);
n=read();
S=0;
nn=n*2+3;
T=n*2+1;
SS=n*2+2;
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
a[i][j]=read();
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
b[i][j]=read();
double l,r,mid;
l=0.0;r=1e5;
for(int i=1;i<=50;++i)
{
mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
if(check(r)) l=r;
printf("%.6lf\n",l);
}