1565: [NOI2009]植物大战僵尸


Time Limit: 10 Sec   Memory Limit: 64 MB

Submit: 2697  

Solved: 1234

[Submit][Status][Discuss]

Description





Input




Output


仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。


Sample Input


3 2
10 0
20 0
-10 0
-5 1 0 0
100 1 2 1
100 0


Sample Output


25


HINT


在样例中, 植物P1,1可以攻击位置(0,0), P2, 0可以攻击位置(2,1)。 
一个方案为,首先进攻P1,1, P0,1,此时可以攻击P0,0 。共得到能源收益为(-5)+20+10 = 25。注意, 位置(2,1)被植物P2,0保护,所以无法攻击第2行中的任何植物。 
【大致数据规模】
约20%的数据满足1 ≤ N, M ≤ 5;
约40%的数据满足1 ≤ N, M ≤ 10;

约100%的数据满足1 ≤ N ≤ 20,1 ≤ M ≤ 30,-10000 ≤ Score ≤ 10000 。










【分析】

拓扑排序去掉环+最大权闭合子图

SBS的坑终于填掉了




【代码】

//NOI 2009 植物大战僵尸 
#include<bits/stdc++.h>
#define inf 1e9
#define mp make_pair
#define ll long long
#define p(i,j) ((i-1)*m+(j))
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=600005;
queue <int> q;
bool vis[mxn],ban[mxn];
int w,n,m,S,T,ans,cnt;
vector < int > F[mxn];
struct edge {int to,next,flow;} f[mxn<<1];
int head[mxn],du[mxn],sco[mxn],num[mxn],dis[mxn];
inline void add(int u,int v,int flow)
{
	f[++cnt]=(edge){v,head[u],flow},head[u]=cnt;
	f[++cnt]=(edge){u,head[v],0},head[v]=cnt;
}
inline bool bfs()
{
	memset(dis,-1,sizeof dis);
	q.push(S),dis[S]=0;
	while(!q.empty())
	{
		int u=q.front();q.pop();
		for(int i=head[u];i;i=f[i].next)
		{
			int v=f[i].to,flow=f[i].flow;
			if(flow>0 && dis[v]==-1)
			  dis[v]=dis[u]+1,q.push(v);
		}
	}
	return dis[T]>0;
}
inline int find(int u,int low)
{
	int i,j,a,sum=0;
	if(u==T) return low;
	for(int i=head[u];i;i=f[i].next)
	{
		int v=f[i].to,flow=f[i].flow;
		if(flow>0 && dis[v]==dis[u]+1 && (a=find(v,min(flow,low-sum))))
		{
			sum+=a;
			f[i].flow-=a;
			if(i&1) f[i+1].flow+=a;
			else f[i-1].flow+=a;
			if(sum==low) return sum;
		}
	}
	if(!sum) dis[u]=-1;
	return sum;
}
inline void topsort()
{
	int i,j,k;
	fo(i,1,n) fo(j,1,m) 
	  if(!du[p(i,j)]) q.push(p(i,j));
	while(!q.empty())
	{
		int u=q.front();q.pop();
		for(int i=0;i<F[u].size();i++)
		{
			int v=F[u][i];
			du[v]--;
			if(!du[v]) q.push(v);
		}
	}
	fo(i,1,n) fo(j,1,m)
	  if(du[p(i,j)]) ban[p(i,j)]=1;
}
int main()
{
	int i,j,k,x,y,u,v;
	scanf("%d%d",&n,&m);
	S=0,T=n*m+1;
	fo(i,1,n) fo(j,1,m)
	{
		scanf("%d",&sco[p(i,j)]);
		scanf("%d",&num[p(i,j)]);
		fo(k,1,num[p(i,j)])
		{
			scanf("%d%d",&u,&v);
			u++,v++;
			du[p(u,v)]++;
			F[p(i,j)].push_back(p(u,v));
		}
	}
	fo(i,1,n) fo(j,1,m-1) F[p(i,j+1)].push_back(p(i,j)),du[p(i,j)]++;
	topsort();
	fo(i,1,n) fo(j,1,m) if(!ban[p(i,j)])
	{
		int u=p(i,j);
		if(sco[u]>0) add(S,u,sco[u]),ans+=sco[u];//,printf("Connect (%d,%d)\n",S,u);
		else add(u,T,-sco[u]);//printf("Connect (%d,%d)\n",u,T);
		for(k=0;k<F[u].size();k++)
		{
			int v=F[u][k];
			if(ban[v]) continue;
			add(v,u,inf);
//			printf("Connect (%d,%d)\n",u,v);
		}
	}
	fo(i,1,n) fo(j,1,m-1) if(!ban[p(i,j)] && !ban[p(i,j+1)])
	  add(p(i,j),p(i,j+1),inf);
	while(bfs()) ans-=find(S,inf);
	printf("%d\n",ans);
	return 0;
}