bzoj3774 最优选择 最小割

版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/85390844

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

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/85390844