Description
小N手上有一个N*M的方格图,控制某一个点要付出Aij的代价,然后某个点如果被控制了,或者他周围的所有点(上下左右)都被控制了,那么他就算是被选择了的。一个点如果被选择了,那么可以得到Bij的回报,现在请你帮小N选一个最优的方案,使得回报-代价尽可能大。
对于100%的数据,N,M<=50,Aij,Bij都是小于等于100的正整数。
Solution
很套路的建图。。
我们先黑白染色并拆点,i和i’连b,i’和临点j’连INF,i和临点j连INF,S向白点入点连a,黑点出点向T点连a
考虑这么做的正确性。一条路径上一定要割一条边,我们割掉的三个位置分别代表了某个点的三种状态:选它,选周围,不选
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
const int INF=0x3f3f3f3f;
const int N=50005;
const int E=1000005;
struct edge {int y,w,next;} e[E];
int dis[N],que[N],id[205][205];
int ls[N],edCnt=1;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y,int w) {
e[++edCnt]=(edge) {y,w,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {x,0,ls[y]}; ls[y]=edCnt;
}
bool bfs(int st,int ed) {
fill(dis,-1);
int h=1,t=1; dis[st]=1;
for (que[1]=st;h<=t;) {
int now=que[h++];
for (int i=ls[now];i;i=e[i].next) {
if (e[i].w>0&&dis[e[i].y]==-1) {
dis[e[i].y]=dis[now]+1;
que[++t]=e[i].y;
if (e[i].y==ed) return true;
}
}
}
return false;
}
int find(int now,int ed,int mn) {
if (now==ed||!mn) return mn;
int ret=0;
for (int i=ls[now];i;i=e[i].next) {
if (e[i].w>0&&dis[now]+1==dis[e[i].y]) {
int d=find(e[i].y,ed,std:: min(mn-ret,e[i].w));
e[i].w-=d; e[i^1].w+=d; ret+=d;
if (ret==mn) break;
}
}
return ret;
}
int dinic(int st,int ed) {
int res=0;
for (;bfs(st,ed);) res+=find(st,ed,INF);
return res;
}
int main(void) {
int n=read(),m=read(),tot=0,ans=0;
rep(i,1,n) rep(j,1,m) id[i][j]=++tot;
rep(i,1,n) rep(j,1,m) {
int x=read(); //ans+=x;
if ((i&1)==(j&1)) {
add_edge(0,id[i][j],x);
} else add_edge(id[i][j]+tot,tot*2+1,x);
}
rep(i,1,n) rep(j,1,m) {
int x=read(); ans+=x;
add_edge(id[i][j],id[i][j]+tot,x);
if ((i&1)==(j&1)) {
if (i>1) {
add_edge(id[i][j],id[i-1][j],INF);
add_edge(id[i][j]+tot,id[i-1][j]+tot,INF);
}
if (i<n) {
add_edge(id[i][j],id[i+1][j],INF);
add_edge(id[i][j]+tot,id[i+1][j]+tot,INF);
}
if (j>1) {
add_edge(id[i][j],id[i][j-1],INF);
add_edge(id[i][j]+tot,id[i][j-1]+tot,INF);
}
if (j<m) {
add_edge(id[i][j],id[i][j+1],INF);
add_edge(id[i][j]+tot,id[i][j+1]+tot,INF);
}
}
}
printf("%d\n", ans-dinic(0,tot*2+1));
return 0;
}