Rt,建出的图中共有 2n+2 个点,n2+2n 条边,所以 maxn=105,maxm=20405,除 a,b 外,用到 maxn 的大小均乘 2。
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int maxn=205;
const int maxm=20405;
int a[maxn][maxn],b[maxn][maxn],d[maxn<<1],now[maxn<<1],head[maxn<<1],ver[maxm],edge[maxm],nxt[maxm],tot,n,m,s,t;
double dis[maxn<<1],cost[maxn<<1],l,r,ans;
bool vis[maxn<<1];
queue<int>q;
void addedge(int u,int v,int w,double c){
ver[++tot]=v;
edge[tot]=w;
cost[tot]=c;
nxt[tot]=head[u];
head[u]=tot;
}
void add_edge(int u,int v,int w,double c){
addedge(u,v,w,c);
addedge(v,u,0,-c);
}
bool spfa(){
for(int i=1;i<=2*n+2;i++){
dis[i]=-1e18;
vis[i]=0;
}
now[s]=head[s];
vis[s]=true;
dis[s]=0;
d[s]=1;
q.push(s);
while(!q.empty()){
int x=q.front();
q.pop();
vis[x]=false;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i],z=edge[i];
double w=cost[i];
if(!z) continue;
if(dis[x]+w>dis[y]){
now[y]=head[y];
dis[y]=dis[x]+w;
d[y]=d[x]+1;
if(!vis[y]){
vis[y]=true;
q.push(y);
}
}
}
}
return dis[t]!=-1e18;
}
int dinic(int x,int flow){
if(x==t) return flow;
int rest=flow;
for(int i=now[x];i&&rest;i=nxt[i]){
now[x]=i;
int y=ver[i],z=edge[i];
double w=cost[i];
if(dis[y]==dis[x]+w&&d[y]==d[x]+1&&z){
int k=dinic(y,min(rest,z));
if(!k) d[y]=0;
edge[i]-=k;
edge[i^1]+=k;
rest-=k;
ans+=(k*w);
}
}
return flow-rest;
}
bool check(double mid){
memset(head,0,sizeof(head));
tot=s=1;
t=2*n+2;
ans=0;
for(int i=1;i<=n;i++)
add_edge(s,i+1,1,0);
for(int i=1;i<=n;i++)
add_edge(n+i+1,t,1,0);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
add_edge(i+1,j+n+1,1,a[i][j]-mid*b[i][j]);
while(spfa()) while(dinic(s,1e9));
return ans>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]);
r=1e6;
for(int i=1;i<=45;i++){
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
printf("%0.6lf",l);
return 0;
}