分析:
二分答案后跑最小割。
连边方式如下:
1、s -> 格子,容量为格子的权值。
2、格子 -> 相邻格,容量为两格之间的格线权值mid。
3、边界格 -> t,容量为该格的边界格线权值mid。
剩下的待会补。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
int n,m,s,t,ecnt,head[2505],cur[2505],dep[2505];
int val[55][55],D[55][55],R[55][55];
int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
double sum,maxflow,mincut;
std::queue<int> q;
struct Edge{
int to,nxt;
double cap;
}e[30005];
inline void add_edge(int bg,int ed,double ca){
ecnt++;
e[ecnt].to=ed;
e[ecnt].nxt=head[bg];
e[ecnt].cap=ca;
head[bg]=ecnt;
}
inline bool bfs(){
memset(dep,0x3f,sizeof dep);
for(int i=1;i<=t;i++) cur[i]=head[i];
while(!q.empty()) q.pop();
dep[s]=1;
q.push(s);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];i!=-1;i=e[i].nxt){
int ver=e[i].to;
if(dep[ver]>1e9&&e[i].cap>0){
dep[ver]=dep[u]+1;
q.push(ver);
}
}
}
return dep[t]<1e9;
}
double dfs(int x,double pref){
if(!pref||x==t) return pref;
double flow=0,temp;
for(int& i=cur[x];i!=-1;i=e[i].nxt){
int ver=e[i].to;
if(dep[ver]==dep[x]+1&&(temp=dfs(ver,std::min(pref,e[i].cap)))){
e[i].cap-=temp;
e[i^1].cap+=temp;
pref-=temp;
flow+=temp;
if(!pref) break;
}
}
return flow;
}
inline void dinic(){
maxflow=0;
while(bfs()){
maxflow+=dfs(s,1e9);
// std::cout<<maxflow<<std::endl;
}
}
inline bool check(double mid){
ecnt=-1;memset(head,-1,sizeof head);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
add_edge(s,(i-1)*m+j,val[i][j]);
add_edge((i-1)*m+j,s,0);
for(int k=1;k<=4;k++){
int xx=i+dx[k],yy=j+dy[k];
if(xx==0){
add_edge((i-1)*m+j,t,D[i-1][j]*mid);
add_edge(t,(i-1)*m+j,0);
}
else if(xx==n+1){
add_edge((i-1)*m+j,t,D[i][j]*mid);
add_edge(t,(i-1)*m+j,0);
}
else if(yy==0){
add_edge((i-1)*m+j,t,R[i][j-1]*mid);
add_edge(t,(i-1)*m+j,0);
}
else if(yy==m+1){
add_edge((i-1)*m+j,t,R[i][j]*mid);
add_edge(t,(i-1)*m+j,0);
}
else{
add_edge((i-1)*m+j,(xx-1)*m+yy,(k<=2?(k==1?D[i-1][j]:D[i][j]):(k==3?R[i][j-1]:R[i][j]))*mid);
add_edge((xx-1)*m+yy,(i-1)*m+j,0);
}
}
}
}
// for(int i=1;i<=t;i++){
// std::cout<<i<<": ";
// for(int j=head[i];j!=-1;j=e[j].nxt)
// std::cout<<"("<<e[j].to<<","<<e[j].cap<<") ";
// std::cout<<std::endl;
// }
// system("pause");
dinic();
mincut=maxflow;
return sum-mincut>0;
}
int main(){
scanf("%d%d",&n,&m);
s=n*m+1;t=s+1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&val[i][j]),sum+=val[i][j];
for(int i=0;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&D[i][j]);
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
scanf("%d",&R[i][j]);
double l=0,r=1250,ans;
while(r-l>1e-6){
// std::cout<<">>>"<<l<<" "<<r<<std::endl;
double mid=(l+r)/2;
if(check(mid)) ans=mid,l=mid;
else r=mid;
}
printf("%.3lf\n",ans);
return 0;
}