将图黑白染色,每个点拆成两个点,分别表示水平和竖直方向,再增加一个点以控制流量,那么每个格子都需要找两个方向去连接。

$S$到每个黑点的控制点连边,流量$2$,费用$0$;

控制点向两个方向的点各连两条边,第一条流量$1$,费用$0$,第二条流量$1$,费用$w$;

然后两个方向的点分别向对应白点连边,流量$1$,费用$0$。

这样一来如果这个格子是直轨道,那么会产生$w$的收益,如果是弯轨道,会产生$2w$的收益。

对于白点也类似处理,求出最大费用最大流,如果满流则有解,最大收益为费用减去总收益。

#include<cstdio>
const int inf=~0U>>2,N=15010,M=300000,E=155;
int n,m,i,j,tmp,flow,ans,cS,cT,a[E][E],b[E][E],id[E][E][3];
int u[M],v[M],c[M],co[M],nxt[M],t=1,S,T,l,r,q[M],g[N],f[N],d[N];bool in[N];
inline void add(int x,int y,int z,int zo){
u[++t]=x;v[t]=y;c[t]=z;co[t]=zo;nxt[t]=g[x];g[x]=t;
u[++t]=y;v[t]=x;c[t]=0;co[t]=-zo;nxt[t]=g[y];g[y]=t;
}
inline bool spfa(){
int x,i;
for(i=1;i<=T;i++)d[i]=-inf,in[i]=0;
d[S]=0;in[S]=1;l=r=M>>1;q[l]=S;
while(l<=r){
x=q[l++];
if(x==T)continue;
for(i=g[x];i;i=nxt[i])if(c[i]&&co[i]+d[x]>d[v[i]]){
d[v[i]]=co[i]+d[x];f[v[i]]=i;
if(!in[v[i]]){
in[v[i]]=1;
if(d[v[i]]>d[q[l]])q[--l]=v[i];else q[++r]=v[i];
}
}
in[x]=0;
}
return d[T]>-inf;
}
int main(){
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)for(j=1;j<=m;j++)scanf("%d",&a[i][j]);
for(i=1;i<=n;i++)for(j=1;j<=m;j++)scanf("%d",&b[i][j]);
for(i=1;i<=n;i++)for(j=1;j<=m;j++){
id[i][j][0]=++T;
id[i][j][1]=++T;
id[i][j][2]=++T;
}
T++;
for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(!a[i][j]){
ans-=b[i][j];
if((i+j)&1){
cS+=2;
add(S,id[i][j][2],2,0);
add(id[i][j][2],id[i][j][0],1,0);
add(id[i][j][2],id[i][j][0],1,b[i][j]);
add(id[i][j][2],id[i][j][1],1,0);
add(id[i][j][2],id[i][j][1],1,b[i][j]);
if(id[i-1][j][0])add(id[i][j][0],id[i-1][j][0],1,0);
if(id[i+1][j][0])add(id[i][j][0],id[i+1][j][0],1,0);
if(id[i][j-1][0])add(id[i][j][1],id[i][j-1][1],1,0);
if(id[i][j+1][0])add(id[i][j][1],id[i][j+1][1],1,0);
}else{
cT+=2;
add(id[i][j][2],T,2,0);
add(id[i][j][0],id[i][j][2],1,0);
add(id[i][j][0],id[i][j][2],1,b[i][j]);
add(id[i][j][1],id[i][j][2],1,0);
add(id[i][j][1],id[i][j][2],1,b[i][j]);
}
}
if(cS!=cT)return puts("-1"),0;
while(spfa()){
for(tmp=inf,i=T;i!=S;i=u[f[i]])if(tmp>c[f[i]])tmp=c[f[i]];
for(ans+=d[i=T]*tmp,flow+=tmp;i!=S;i=u[f[i]])c[f[i]]-=tmp,c[f[i]^1]+=tmp;
}
if(flow!=cS)return puts("-1"),0;
return printf("%d",ans),0;
}

  

04-23 22:48