题目大意:
有个(n*m)的网格图
每个点可以选择(A),获得(A[i][j])或选(B)获得(B[i][j])的收益
相邻点有(k)个不同可以获得(C[i][j])的收益,求最大收益
类似与文理分科那题,不过这次是相邻不同有额外收益,需要稍微变形一下
我们把网格黑白染色
对于黑色点向(S)连(A[i][j])边,向汇点连(B[i][j])边
对于白色点向(S)连(B[i][j])边,向汇点连(A[i][j])边
然后对于相邻点互相连(C[x][y]+C[tx][ty])边
这样满足相邻格子选择相同类型时需要鸽掉中间边
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0,f=1;
char ch;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=0,ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?x:-x;
}
const int inf=0x3f3f3f3f;
int dx[5]={0,-1,0,1,0},dy[5]={0,0,1,0,-1};
int n,m,sum,tot,st,ed,ret;
int val[110][110][3];
int id[110][110];
bool col[110][110];
int head[100010],cur[100010],d[10000],cnt=1;
struct point
{
int nxt,to,c;
}a[200010];
inline void add(int x,int y,int c)
{
a[++cnt]=(point){head[x],y,c};head[x]=cnt;
a[++cnt]=(point){head[y],x,0};head[y]=cnt;//大草
}
queue<int> q;
inline bool bfs()
{
for(int i=1;i<=tot;++i)
{
cur[i]=head[i];
d[i]=0;
}
q.push(st);d[st]=1;
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=head[now];i;i=a[i].nxt)
{
int t=a[i].to;
if(!d[t]&&a[i].c)
{
d[t]=d[now]+1;
q.push(t);
}
}
}
return d[ed];
}
inline int dfs(int now,int c)
{
if(now==ed||!c) return c;
int ret=c,f;
for(int i=cur[now];i;i=a[i].nxt)
{
cur[now]=i;
int t=a[i].to;
if(d[t]==d[now]+1)
{
f=dfs(t,min(a[i].c,ret));
if(!f) continue;
a[i].c-=f;
a[i^1].c+=f;
ret-=f;
if(!ret) return c;
}
}
if(ret==c) d[now]=0;
return c-ret;
}
inline int dinic()
{
int ret=0;
while(bfs()) ret+=dfs(st,inf);
return ret;
}
signed main()//黑白染色,黑点源点连a[i][j]边,汇点连b[i][j]边,四周连c[i][j]+c[tx][ty]边
{
n=read(),m=read();
for(int k=0;k<=2;++k)
{
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
val[i][j][k]=read();
if(!k) id[i][j]=++tot,col[i][j]=((i+j)&1);
}
}
}
st=++tot,ed=++tot;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
sum+=val[i][j][0]+val[i][j][1];
add(st,id[i][j],val[i][j][col[i][j]^1]);
add(id[i][j],ed,val[i][j][col[i][j]]);
for(int k=1;k<=4;++k)
{
int tx=i+dx[k],ty=j+dy[k];
if(tx<1||ty<1||tx>n||ty>m) continue;
add(id[i][j],id[tx][ty],val[i][j][2]+val[tx][ty][2]);//选相同的种类会割掉中间边,很稳
sum+=val[i][j][2];
}
}
}
printf("%d
",sum-dinic());
return 0;
}