传送门
最小割经典题目。
题目让我们求最大的贡献。
那我们先考虑加上全部的贡献,然后求出最小的需要丢掉的贡献。
那么这个时候,如果没有限制就已经是最小割的典型模型了。
即直接建边 ( s , p o s i , j , a r t i , j ) , ( p o s i , j , t , a r t i , j ) (s,pos_{i,j},art_{i,j}),(pos_{i,j},t,art_{i,j}) (s,posi,j,arti,j),(posi,j,t,arti,j)
这样求最小割是正确的。
现在有了满意值,怎么做呢?
直接分类讨论就行了。
学理是同理的。
按照这个来建边就行了:
( s , p o s i , j ′ , s a m e (s,pos'_{i,j},same (s,posi,j′,same_ a r t i , j ) , ( p o s i , j ′ , p o s i ′ , j ′ , i n f ) art_{i,j}),(pos'_{i,j},pos_{i',j'},inf) arti,j),(posi,j′,posi′,j′,inf),其中 ( i , j ) , ( i ′ , j ′ ) (i,j),(i',j') (i,j),(i′,j′)是相邻的。
理科同理。
这样子割出来一定是对的。
可以画个图来分类验证。
代码:
#include
#define M 1000005
#define N 40005
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
int n,m,tim[505][505],Clocks=0,ans=0,dx[5]={0,0,0,-1,1},dy[5]={0,-1,1,0,0};
struct edge{int v,next,c;};
struct Dinic{
edge e[M<<1];
int first[N],cur[N],cnt,s,t,d[N];
inline void addedge(int u,int v,int c){e[++cnt].v=v,e[cnt].c=c,e[cnt].next=first[u],first[u]=cnt;}
inline void add(int u,int v,int c){addedge(u,v,c),addedge(v,u,0);}
inline void init(){memset(first,-1,sizeof(first)),cnt=-1,s=0,t=n*m*3+1;}
inline bool bfs(){
queue<int>q;
for(int i=1;i<=t;++i)d[i]=-1;
q.push(s);
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=first[x];~i;i=e[i].next){
int v=e[i].v;
if(~d[v]||!e[i].c)continue;
d[v]=d[x]+1,q.push(v);
}
}
return ~d[t];
}
inline int dfs(int x,int f){
if(x==t||!f)return f;
int flow=f;
for(int&i=cur[x];~i;i=e[i].next){
int v=e[i].v;
if(!flow)break;
if(e[i].c&&d[v]==d[x]+1){
int tmp=dfs(v,min(flow,e[i].c));
if(!tmp)d[v]=-1;
e[i].c-=tmp,e[i^1].c+=tmp,flow-=tmp;
}
}
return f-flow;
}
inline int solve(){
int ret=0;
while(bfs())memcpy(cur,first,sizeof(first)),ret+=dfs(s,0x3f3f3f3f);
return ret;
}
}dinic;
int main(){
n=read(),m=read(),dinic.init();
for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)tim[i][j]=++Clocks;
for(int i=1;i<=n;i++)for(int val,j=1;j<=m;++j)val=read(),dinic.add(dinic.s,tim[i][j],val),ans+=val;
for(int i=1;i<=n;++i)for(int val,j=1;j<=m;++j)val=read(),dinic.add(tim[i][j],dinic.t,val),ans+=val;
for(int i=1;i<=n;++i)for(int val,j=1;j<=m;++j){
val=read(),dinic.add(dinic.s,tim[i][j]+n*m,val),ans+=val;
for(int k=0;k<=4;++k){
int mx=dx[k]+i,my=dy[k]+j;
if(!mx||!my||mx>n||my>m)continue;
dinic.add(tim[i][j]+n*m,tim[mx][my],0x3f3f3f3f);
}
}
for(int i=1;i<=n;++i)for(int val,j=1;j<=m;++j){
val=read(),dinic.add(tim[i][j]+2*n*m,dinic.t,val),ans+=val;
for(int k=0;k<=4;++k){
int mx=dx[k]+i,my=dy[k]+j;
if(!mx||!my||mx>n||my>m)continue;
dinic.add(tim[mx][my],tim[i][j]+2*n*m,0x3f3f3f3f);
}
}
cout<<ans-dinic.solve();
return 0;
}