bzoj3774 最優選擇 最小割
阿新 • • 發佈:2018-12-30
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;
}