题解:首先肯定是分数规划这没问题,然后在于怎么建边,怎么确定二分方向,即“check”。
建图:好吧其实我也没弄懂建图到底怎么回事,自责一下。但是依然要贴一下代码,如果不求甚解的话这么建图代码肯定是又快又短的,当然,如果谁弄懂了给个回复!
codes:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 500
#define NN 50000
#define M 301000
#define inf 200000000.0
#define eps 1e-5
using namespace std;
struct KSD
{
int u,v,next;
double len;
}e[M];
int head[NN],id[N][N],d[NN],n,m,s,t,cnt;
double cross[N][N],stand[N][N],w[N][N],sum,maxflow;
void add(int u,int v,double len)
{
cnt++;
e[cnt].u=u;
e[cnt].v=v;
e[cnt].len=len;
e[cnt].next=head[u];
head[u]=cnt;
}
void edit(double mid)
{
int i,j;
cnt=1;maxflow=0;
memset(head,0,sizeof(head));
memset(e,0,sizeof(e));
for(i=0;i<=n+1;i++)for(j=0;j<=m+1;j++)
{
if(i<1||i>n||j<1||j>m)
{
add(id[i][j],t,inf);
add(t,id[i][j],0);
}
else
{
add(s,id[i][j],w[i][j]);
add(id[i][j],s,0);
}
}
for(i=0;i<=n;i++)
{
for(j=1;j<=m;j++)
{
add(id[i][j],id[i+1][j],mid*cross[i][j]);
add(id[i+1][j],id[i][j],mid*cross[i][j]);
}
}
for(i=1;i<=n;i++)
{
for(j=0;j<=m;j++)
{
add(id[i][j],id[i][j+1],mid*stand[i][j]);
add(id[i][j+1],id[i][j],mid*stand[i][j]);
}
}
}
void build()
{
int i,j;
cnt=0;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
scanf("%lf",&w[i][j]);
sum+=w[i][j];
}
}
for(i=0;i<=n+1;i++)
{
for(j=0;j<=m+1;j++)
{
id[i][j]=++cnt;
}
}
for(i=0;i<=n;i++)
{
for(j=1;j<=m;j++)
{
scanf("%lf",&cross[i][j]);
}
}
for(i=1;i<=n;i++)
{
for(j=0;j<=m;j++)
{
scanf("%lf",&stand[i][j]);
}
}
s=0,t=cnt+1;
}
int bfs()
{
int i,u,v;
memset(d,0,sizeof(d));
queue<int>q;
q.push(s);
d[s]=1;
while(!q.empty())
{
u=q.front();
q.pop();
for(i=head[u];i;i=e[i].next)
{
v=e[i].v;
if(d[v]||e[i].len<eps)continue;
d[v]=d[u]+1;
if(v==t)return 1;
q.push(v);
}
}
return 0;
}
double dinic(int x,double f)
{
if(x==t)return f;
int i,v;
double remain=f,k;
for(i=head[x];i&&remain>=eps;i=e[i].next)
{
v=e[i].v;
if(e[i].len>=eps&&d[v]==d[x]+1)
{
k=dinic(v,min(remain,e[i].len));
if(k<eps)d[v]=0;
else
{
e[i].len-=k;
e[i^1].len+=k;
remain-=k;
}
}
}
return f-remain;
}
int main()
{
// freopen("test.in","r",stdin);
int i;
double l,r,mid;
build();
l=0,r=n*m*100.0,mid=n*m*50.0;
for(i=1;i<=35;i++,mid=(l+r)/2.0)
{
edit(mid);
while(bfs())maxflow+=dinic(s,inf);
if (sum-maxflow<=1e-9)r=mid;
else l=mid;
}
printf("%.3lf",l);
return 0;
}