题目链接:https://loj.ac/problem/2003
代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=500;
const int MAXM=1e5+5;
const int INF=0x3f3f3f3f;
const double eps=1e-8;
int a[105][105],b[105][105],n;
namespace MCMF
{
struct Edge
{
int to,next,cap,flow;
double cost;
}edge[MAXM];
int head[MAXN],tol;
int pre[MAXN];
double dis[MAXN];
bool vis[MAXN];
int N;//节点总个数,节点编号从0~N-1
void init(int n)
{
N=n;
tol=0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int cap,double cost)
{
edge[tol].to=v;edge[tol].cap=cap;edge[tol].cost=cost;edge[tol].flow=0;edge[tol].next=head[u];
head[u]=tol++;
edge[tol].to=u;edge[tol].cap=0;edge[tol].cost=-cost;edge[tol].flow=0;edge[tol].next=head[v];
head[v]=tol++;
}
bool spfa(int s,int t)
{
queue<int>q;
for(int i=0;i<N;i++)
{
dis[i]=INF;
vis[i]=false;
pre[i]=-1;
}
dis[s]=0;
vis[s]=true;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=false;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(edge[i].cap>edge[i].flow&&dis[v]>dis[u]+edge[i].cost)
{
dis[v]=dis[u]+edge[i].cost;
pre[v]=i;
if(!vis[v])
{
vis[v]=true;
q.push(v);
}
}
}
}
if(pre[t]==-1)
return false;
else
return true;
}
//返回的是最大流,cost存的是最小费用
int minCostMaxflow(int s,int t,double &cost)
{
int flow=0;
cost=0;
while(spfa(s,t))
{
int Min=INF;
for(int i=pre[t];i!=-1;i=pre[edge[i^1].to])
{
if(Min>edge[i].cap-edge[i].flow)
Min=edge[i].cap-edge[i].flow;
}
for(int i=pre[t];i!=-1;i=pre[edge[i^1].to])
{
edge[i].flow+=Min;
edge[i^1].flow-=Min;
cost+=edge[i].cost*Min;
}
flow+=Min;
}
return flow;
}
}
bool judge(double c)
{
MCMF::init(2*n+2);
for(int i=1;i<=n;i++)
{
MCMF::addedge(0,i,1,0);
for(int j=1;j<=n;j++)
{
MCMF::addedge(i,n+j,1,-(a[i][j]-c*b[i][j]));
}
MCMF::addedge(n+i,n+n+1,1,0);
}
double cost=0;
MCMF::minCostMaxflow(0,n+n+1,cost);
return cost<eps;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
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]);
}
}
double l=0,r=100000,ans;
int cnt=40;
while(cnt--)
{
double mid=(l+r)/2;
if(judge(mid))
{
ans=mid;
l=mid;
}
else
{
r=mid;
}
}
printf("%.6lf\n",ans);
return 0;
}