bzoj1565

1565: [NOI2009]植物大战僵尸

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 2916  Solved: 1330
[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 。

  一道比较裸的最大权闭合子图问题吧。重点是处理环!!

  如果a保护b,那么选了b必选a,对应到最大权闭合子图里,就是b->a建边。

  最大权闭合子图问题具体看blog
  https://www.cnblogs.com/wuyiqi/archive/2012/03/12/2391960.html

  

  此题有环,考虑到成环的植物是不可能被啃食的,所以去掉环中的点,建立新图。处理环可以用topsort。
  注意topsort的时候还是按照 a保护b a->b来建边
  最后跑maxflow才改成b->a
  原因:一个有向图所有边反向,有可能原图的环会改变

  那么例子是ZJ给出的:

              

  然后这个题就被gay了

/*
注意topsort的时候还是按照 a保护b a->b来建边
最后跑maxflow才改成b->a
原因:一个有向图所有边反向,有可能原图的环会改变 
*/

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#define inf 0x3f3f3f3f
#define ll long long
#define N 605
using namespace std;
int n,m,sum,tot,S,T,sc[N],in[N],ok[N],cur[N],hd[N],vis[N],d[N];
struct edge{int v,next,cap;}e[N*N*2];
vector<int>g[N];queue<int>q;
void adde(int u,int v,int c){
	e[tot].v=v;
	e[tot].next=hd[u];
	e[tot].cap=c;
	hd[u]=tot++;
}
void topsort(){
	for(int i=1;i<T;i++){
		if(!in[i])
		ok[i]=1,q.push(i);
	}
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=0;i<g[u].size();i++){
			int v=g[u][i];--in[v];
			if(!in[v]){
				ok[v]=1;
				q.push(v);
			}
		}
	}
}
bool bfs(){
	memset(vis,0,sizeof(vis));
	d[S]=0;vis[S]=1;q.push(S);
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=hd[u];~i;i=e[i].next){
			int v=e[i].v;
			if(e[i].cap&&!vis[v]){
				vis[v]=1;
				d[v]=d[u]+1;
				q.push(v);
			}
		}
	}
	return vis[T];
}
int dfs(int u,int a){
	if(u==T||!a)return a;
	int fl=0,f;
	for(int &i=cur[u];~i;i=e[i].next){
		int v=e[i].v;
		if(e[i].cap&&d[v]==d[u]+1&&(f=dfs(v,min(e[i].cap,a)))){
			fl+=f;a-=f;e[i].cap-=f;
			e[i^1].cap+=f;if(!a)break;
		}
	}
	return fl;
}

int main(){
#ifdef wsy
	freopen("data.in","r",stdin);
#else
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
#endif
	memset(hd,-1,sizeof(hd));
	scanf("%d%d",&n,&m);S=0;T=n*m+1;
	for(int i=1;i<T;i++){
		int c,x,y,id;
		scanf("%d%d",&sc[i],&c);
		for(int j=1;j<=c;j++){
			scanf("%d%d",&x,&y);
			x++;y++;
			id=(x-1)*m+y;
			g[i].push_back(id);
			in[id]++;
		//	printf("%d %d
",i,id);
		}
		if(i%m)g[i+1].push_back(i),in[i]++/*,printf("%d %d
",i+1,i)*/;
	}
	topsort();
	for(int i=1;i<T;i++){
		if(!ok[i])continue;
		for(int j=0;j<g[i].size();j++){
			int v=g[i][j];
			if(!ok[v])continue;
			adde(v,i,inf);adde(i,v,0);
		//	printf("%d %d %d
",i,v,inf);
		}
	}
	for(int i=1;i<T;i++){
		if(sc[i]>0&&ok[i])sum+=sc[i];
		if(sc[i]>0&&ok[i])adde(S,i,sc[i]),adde(i,S,0)/*,printf("%d %d %d
",S,i,sc[i])*/;
		if(sc[i]<0&&ok[i])adde(i,T,-sc[i]),adde(T,i,0)/*,printf("%d %d %d
",i,T,-sc[i])*/;
	}
	int flow=0;
	while(bfs()){
		for(int i=S;i<=T;i++)cur[i]=hd[i];
		flow+=dfs(S,inf);
	}
	printf("%d",sum-flow);
	return 0;
}

  

原文地址:https://www.cnblogs.com/wsy01/p/7921408.html