BZOJ2132 圈地计划

传送~

来自y_immortal学长的网络流推荐2333

建模比较神仙qwq

首先可以建立最小割模型 ->二选一

就是我们处理不同的贡献不好处理 那么我们考虑怎么把它变成相同的贡献

对于原图我们进行黑白染色 然后如果一个点属于T集我们让它反色就可以做到相同的有贡献

那么很明显这个贡献是双向的 对于两个点之间的贡献是相加的

所以我们这样做最小割就可以辣~

代码。

//Love and Freedom.
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define inf 20021225
#define ll long long
#define M 200000
#define N 30000
using namespace std;

struct edge{int to,lt,f;}e[M];
int in[N],cnt=1,dep[N];
int s,t;
void add(int x,int y,int f)
{
	e[++cnt].to = y; e[cnt].lt = in[x]; e[cnt].f = f; in[x] = cnt;
	e[++cnt].to = x; e[cnt].lt = in[y]; e[cnt].f = 0; in[y] = cnt;
}
queue<int> q;
bool bfs()
{
	while(!q.empty())	q.pop();
	memset(dep,0,sizeof(dep));
	dep[s] = 1; q.push(s);
	while(!q.empty())
	{
		int x = q.front(); q.pop();
		for(int i=in[x];i;i=e[i].lt)
		{
			int y = e[i].to;
			if(!dep[y] && e[i].f)
			{
				dep[y] = dep[x]+1;	q.push(y);
				if(dep[t])	return true;
			}
		}
	}
	return false;
}

int dfs(int x,int f)
{
	if(x==t||!f)	return f;
	int cur = f;
	for(int i=in[x];i;i=e[i].lt)
	{
		int y = e[i].to;
		if(dep[y] == dep[x]+1 && e[i].f)
		{
			int flow = dfs(y,min(cur,e[i].f));
			e[i].f -= flow; e[i^1].f += flow;
			cur -= flow; if(cur==0)	return f;
		}
	}
	dep[x] = -1;
	return f-cur;
}

int dinic()
{
	int ans = 0;
	while(bfs())	ans+=dfs(s,inf);
	return ans;
}
int n,m;
int id(int x,int y)
{
	return (x-1)*m + y;
}
int a[101][101];
int b[101][101];
int c[101][101];
int xx[4] = {0,0,1,-1};
int yy[4] = {1,-1,0,0};
int main()
{
	int fin = 0;
	scanf("%d%d",&n,&m);
	s = n*m*2; t = s+1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			scanf("%d",&a[i][j]);
			if((i+j)&1)	add(s,id(i,j),a[i][j]);
			else	add(id(i,j),t,a[i][j]);
			fin+=a[i][j];
		}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			scanf("%d",&b[i][j]);
			if((i+j)&1)	add(id(i,j),t,b[i][j]);
			else	add(s,id(i,j),b[i][j]);
			fin+=b[i][j];
		}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&c[i][j]);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			for(int k=0;k<4;k++)
			{
				int x = i+xx[k], y = j+yy[k];
				if(x<1||y<1||x>n||y>m)	continue;
				int val = c[i][j] + c[x][y];
				add(id(i,j),id(x,y),val);
				fin+=c[i][j];
			}
	printf("%d\n",fin-dinic());
	return 0;
}

 

posted @ 2019-01-18 15:26  寒雨微凝  阅读(114)  评论(0编辑  收藏  举报