【NOI2009-DAY2-T1】【BZOJ1565】—植物大战僵尸(最大权闭合子图+拓扑排序)

传送门

估计是当天签到题

考虑到如果一株植物AA被另一株植物BB给保护着,那就必须要先吃掉植物BB才可以吃掉AA,

那考虑我们将所有被保护的植物向保护其的植物连一条边,表示要吃掉保护它的植物
那么我们现在就相当于是在找图的一个权闭合子图了(如果不会或是不知道的权闭合子图的自行百度吧)

从源点向所有贡献为正的点连一条边权为点权的边,所有贡献为负的点向汇点连一条边权为点权绝对值的边

这样跑出来的最大流=最小割=最大权闭合子图

但注意到有可能保护关系形成了一个环,这时候显然是不可能攻击环上植物的

先拓扑排序排除一下环就是了

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	char ch=getchar();
	int res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
	return res*f;
}
const int N=805;
const int M=1000005;
const int inf=19260817;
int n,m,cnt=1,adj[N],nxt[M<<1],to[M<<1],cap[M<<1],val[N],in[N],lev[N],vis[N],tp[N],str,des,ans;
inline int pos(int x,int y){
	return (y-1)*m+x;
}
inline void addedge(int u,int v,int w){
	nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,cap[cnt]=w;
	nxt[++cnt]=adj[v],adj[v]=cnt,to[cnt]=u,cap[cnt]=0;
}
inline void topsort(){
	queue<int> q;
	for(int i=1;i<=n*m;i++){
		if(!in[i])q.push(i);
	}
	while(!q.empty()){
		int u=q.front();q.pop();vis[u]=1;
		for(int e=adj[u];e;e=nxt[e]){
			int v=to[e];
			in[v]--;
			if(!in[v])q.push(v);
		}
	}
}
inline bool bfs(){
	memset(lev,-1,sizeof(lev));
	queue<int> q;
	q.push(str),lev[str]=0;
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int e=adj[u];e;e=nxt[e]){
			int v=to[e];
			if(cap[e]>0&&vis[v]&&lev[v]==-1){
				lev[v]=lev[u]+1;
				q.push(v);
				if(v==des)return true;
			}
		}
	}
	return false;
}
int dinic(int u,int flow){
	if(u==des)return flow;
	int res=0;
	for(int &e=tp[u];e;e=nxt[e]){
		int v=to[e];
		if(cap[e]>0&&vis[v]&&lev[v]==lev[u]+1){
			int mn=dinic(v,min(flow-res,cap[e]));
			res+=mn,cap[e]-=mn,cap[e^1]+=mn;
		}
	}
	return res;
}
inline int solve(){
	int res=0;
	while(bfs()){
		memcpy(tp,adj,sizeof(adj));
		res+=dinic(str,inf);
	}
	return res;
}
int main(){
	n=read(),m=read();str=n*m+1,des=str+1;
	for(int i=1;i<=m*n;i++){
		val[i]=read();
		int w=read();
		for(int j=1;j<=w;j++){
			int y=read()+1,x=read()+1;
			addedge(pos(x,y),i,inf);in[pos(x,y)]++;
		}
		if(i%m){
			addedge(i,i+1,inf);in[i]++;
		}
	}
	topsort();
	vis[str]=vis[des]=1;
	for(int i=1;i<=n*m;i++){
		if(!vis[i])continue;
		if(val[i]>0)addedge(str,i,val[i]),ans+=val[i];
		if(val[i]<0)addedge(i,des,-val[i]);
	}
	cout<<(ans-solve())<<'\n';
}
posted @ 2019-01-27 14:27  Stargazer_cykoi  阅读(105)  评论(0编辑  收藏  举报