1. 程式人生 > >bzoj3774 最優選擇 最小割

bzoj3774 最優選擇 最小割

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; }