【BZOJ1565】【NOI2009】植物大战僵尸 网络流 最大权闭合子图

题目大意

​  给你一个\(n\times m\)的地图,每个格子上都有一颗植物,有的植物能保护其他植物。僵尸从右往左进攻,每吃掉一颗植物就可以得到\(a_{i,j}\)的收益(\(a_{i,j}\)可以是负数)。求僵尸的最大收益

​  \(1\leq n\leq20,1\leq m\leq30\)

题解

​  这种一个东西可以保护另一个东西而且数据范围那么小的题目显然是最大权闭合子图。

​  僵尸从右往左进攻,所以一棵植物可以保护它左边的植物。

​  如果保护关系形成一个环,就都不能选。

​  直接套模板即可。

​  可能需要一些优化

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
struct list
{
	int v[1000010];
	int w[1000010];
	int t[1000010];
	int h[1010];
	int n;
	list()
	{
		memset(h,0,sizeof h);
		n=0;
	}
	void add(int x,int y,int z)
	{
		n++;
		v[n]=y;
		w[n]=z;
		t[n]=h[x];
		h[x]=n;
	}
};
list l,l2;
void add(int x,int y,int z)
{
	l.add(x,y,z);
	l.add(y,x,0);
}
int n,m;
int w[110][110];
int gx[1010];
int gy[1010];
int id(int x,int y)
{
	return (x-1)*m+y;
}
int vis[1010];
int b[1010];
void dfs(int x)
{
	vis[x]=1;
	int i;
	for(i=l2.h[x];i;i=l2.t[i])
	{
		if(!vis[l2.v[i]])
			dfs(l2.v[i]);
		if(b[l2.v[i]]||vis[l2.v[i]]==1)
		{
//			w[gx[x]][gy[x]]=-10000000;
			b[x]=1;
		}
	}
	vis[x]=2;
}
int d[1010];
int S,T;
int c[30][40][30][40];
int bfs()
{
	memset(d,-1,sizeof d);
	queue<int> q;
	q.push(S);
	d[S]=0;
	int x,i;
	while(!q.empty())
	{
		x=q.front();
		q.pop();
		for(i=l.h[x];i;i=l.t[i])
			if(l.w[i]&&d[l.v[i]]==-1)
			{
				d[l.v[i]]=d[x]+1;
				if(l.v[i]==T)
					return 1;
				q.push(l.v[i]);
			}
	}
	return 0;
}
int op(int x)
{
	return ((x-1)^1)+1;
}
int dfs(int x,int flow)
{
	if(x==T)
		return flow;
	int c,s=0,i;
	for(i=l.h[x];i;i=l.t[i])
		if(l.w[i]&&d[l.v[i]]==d[x]+1)
		{
			c=dfs(l.v[i],min(flow,l.w[i]));
			s+=c;
			flow-=c;
			l.w[i]-=c;
			l.w[op(i)]+=c;
			if(!flow)
				break;
		}
	if(flow)
		d[x]=-1;
	return s;
}
int main()
{
	memset(b,0,sizeof b);
	memset(c,0,sizeof c);
//	freopen("bzoj1565.in","r",stdin);
//	freopen("bzoj1565.out","w",stdout);
	scanf("%d%d",&n,&m);
	S=n*m+1;
	T=S+1;
	int sum=0;
	int i,j,k,o,x,y,u;
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)
		{
			scanf("%d",&w[i][j]);
			gx[id(i,j)]=i;
			gy[id(i,j)]=j;
			scanf("%d",&u);
			for(k=1;k<=u;k++)
			{
				scanf("%d%d",&x,&y);
				x++;
				y++;
				c[i][j][x][y]=1;
			}
			if(j>1)
				c[i][j][i][j-1]=1;
			for(x=1;x<=n;x++)
				for(y=1;y<=m;y++)
					if(c[i][j][x][y])
						l2.add(id(x,y),id(i,j),0);
		}
	memset(vis,0,sizeof vis);
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)
			if(!vis[id(i,j)])
				dfs(id(i,j));
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)	
			if(!b[id(i,j)])
			{
				if(w[i][j]>0)
				{
					sum+=w[i][j];
					add(S,id(i,j),w[i][j]);
				}
				else
					add(id(i,j),T,-w[i][j]);
				for(x=1;x<=n;x++)
					for(y=1;y<=m;y++)
						if(c[i][j][x][y])
							if(!b[id(x,y)])
								add(id(x,y),id(i,j),0x7fffffff);
			}
	int ans=0;
	while(bfs())
		ans+=dfs(S,0x7fffffff);
	printf("%d\n",sum-ans);
	return 0;
}
posted @ 2018-03-05 18:46  ywwyww  阅读(317)  评论(0编辑  收藏  举报