[NOI2009]植物大战僵尸

Description:

给你一个n*m的地图,每个位置上有一棵植物,要吃到一行中左边的必须先吃掉右边的

给定每个植物的分数,以及一些植物可以攻击到的位置(你不能经过这些位置)

问能获取到的最大分数是多少

Hint:

\(n,m \le 20\)

Solution:

发现我们要吃一个处在被攻击位置的植物,就要先吃掉那个攻击者

并且要吃左边必须先吃右边,这符合最大权闭合子图的定义,可以建图直接跑

但是有个问题,"保护"关系可能成环,于是要先拓扑排序判掉一些不可能吃到的点

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1 
#define rs p<<1|1
using namespace std;
typedef long long ll;
const int mxn=1e3+5,inf=1e9;
int n,m,S,T,cnt,cnt1,ans,sum,in[mxn],hd[mxn],hd1[mxn],dep[mxn],val[mxn],del[mxn],cur[mxn];

inline int read() {
	char c=getchar(); int x=0,f=1;
	while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
	while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
	return x*f;
}
inline void chkmax(int &x,int y) {if(x<y) x=y;}
inline void chkmin(int &x,int y) {if(x>y) x=y;}

struct ed {
	int to,nxt,w;
}t1[mxn<<1],t[mxn<<1];

inline void add1(int u,int v) {
	t1[++cnt1]=(ed) {v,hd1[u]}; hd1[u]=cnt1; ++in[v];
}

inline void add2(int u,int v,int w) {
	t[cnt]=(ed) {v,hd[u],w}; hd[u]=cnt++;
	t[cnt]=(ed) {u,hd[v],0}; hd[v]=cnt++;
}

void Topsort() {
	queue<int > q;
	for(int i=1;i<=n*m;++i) 
		if(!in[i]) q.push(i); 
		else del[i]=1;
	while(!q.empty()) {
		int u=q.front(); q.pop(); del[u]=0;
		for(int i=hd1[u];i;i=t1[i].nxt) {
			int v=t1[i].to; --in[v];
			if(!in[v]) q.push(v);
		}
	}
}

void init() {
	cnt=0; S=0; T=n*m+1;
	for(int i=1;i<=n*m;++i) 
		if(!del[i]) {
			if(val[i]>0) {
				sum+=val[i];
				add2(S,i,val[i]);
			}
			else add2(i,T,-val[i]);
			for(int j=hd1[i];j;j=t1[j].nxt) {
				int v=t1[j].to;
				if(!del[v]) add2(v,i,inf);
			}
		}	
}

int bfs() {
	memset(dep,0,sizeof(dep)); queue<int > q;
	q.push(S); dep[S]=1;
	for(int i=1;i<=n*m;++i) cur[i]=hd[i];
	while(!q.empty()) {
		int u=q.front(); q.pop();
		for(int i=hd[u];i!=-1;i=t[i].nxt) {
			int v=t[i].to;
			if(dep[v]==0&&t[i].w>0) 
				dep[v]=dep[u]+1,q.push(v);
		}
	}
	if(dep[T]==0) return 0;
	return 1;
}

int dfs(int u,int f) {
	if(u==T) return f;
	for(int &i=cur[u];i!=-1;i=t[i].nxt) {
		int v=t[i].to;
		if(dep[v]==dep[u]+1&&t[i].w>0) {
			int tp=dfs(v,min(f,t[i].w));
			if(tp>0) {
				t[i].w-=tp;
				t[i^1].w+=tp;
				return tp;
			}
		}
	}
	return 0;
}

void Dinic() {
	while(bfs())
		while(int tp=dfs(S,inf)) 
			ans+=tp;
}

int main()
{
	n=read(); m=read(); 
	int a,b,w; memset(hd,-1,sizeof(hd));
	for(int i=1;i<=n;++i) 
		for(int j=1;j<=m;++j) {
			int x=(i-1)*m+j;
			val[x]=read(); w=read();
			while(w--) {
				a=read(); b=read(); ++a,++b;
				int y=(a-1)*m+b; add1(x,y);
			}
		}
	for(int i=1;i<=n;++i) 
		for(int j=2;j<=m;++j) {
			int x=(i-1)*m+j,y=x-1;
			add1(x,y); 
		}
	Topsort(); init(); Dinic();
	printf("%d",sum-ans);
    return 0;
}

posted @ 2019-03-24 18:13  cloud_9  阅读(152)  评论(0编辑  收藏  举报