题解:首先肯定是分数规划这没问题,然后在于怎么建边,怎么确定二分方向,即“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; }