2018.10.10 bzoj1497: [NOI2006]最大获利(最大权闭合子图)

传送门
最大权闭合子图入门题。


把点的花费看成负权值,跟汇点连边: ( i , p i ) (i,p_i) (i,pi)=> ( i , t , p i ) (i,t,p_i) (i,t,pi)
对于边 ( u , v , w ) (u,v,w) (u,v,w),连 ( s , n e w n o d e , w ) , ( n e w n o d e , u , i n f ) , ( n e w n o d e , v , i n f ) (s,newnode,w),(newnode,u,inf),(newnode,v,inf) (s,newnode,w),(newnode,u,inf),(newnode,v,inf)
然后跑最大权闭合子图即可。
代码:

#include
#define N 200005
using namespace std;
inline int read(){
	int ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans;
}
int n,m,ans=0,tot;
struct edge{int v,c,next;};
struct Dinic{
	int first[N],cur[N],s,t,cnt,d[N];
	edge e[N<<1];
	inline void init(){cnt=-1,memset(first,-1,sizeof(first)),s=0,t=N-5;}
	inline void addedge(int u,int v,int c){e[++cnt].v=v,e[cnt].next=first[u],e[cnt].c=c,first[u]=cnt;}
	inline void add(int u,int v,int c){addedge(u,v,c),addedge(v,u,0);}
	inline bool bfs(){
		queue<int>q;
		memset(d,-1,sizeof(d)),q.push(s),d[s]=0;
		while(!q.empty()){
			int x=q.front();
			q.pop();
			for(int i=first[x];~i;i=e[i].next){
				int v=e[i].v;
				if(!e[i].c||~d[v])continue;
				d[v]=d[x]+1,q.push(v);
			}
		}
		return ~d[t];
	}
	inline int dfs(int x,int f){
		if(!f||x==t)return f;
		int flow=f;
		for(int i=first[x];~i;i=e[i].next){
			int v=e[i].v;
			if(!flow)break;
			if(d[v]==d[x]+1&&e[i].c){
				int tmp=dfs(v,min(flow,e[i].c));
				if(!tmp)d[v]=-1;
				e[i].c-=tmp,e[i^1].c+=tmp,flow-=tmp;
			}
		}
		return f-flow;
	}
	inline int solve(){
		int ret=0;
		while(bfs())ret+=dfs(s,0x3f3f3f3f);
		return ret;
	}
}dinic;
int main(){
	n=read(),m=read(),dinic.init(),tot=n;
	for(int i=1,p;i<=n;++i)dinic.add(i,dinic.t,read());
	for(int a,b,c,i=1;i<=m;++i){
		++tot,a=read(),b=read(),ans+=(c=read());
		dinic.add(tot,a,0x3f3f3f3f),dinic.add(tot,b,0x3f3f3f3f),dinic.add(dinic.s,tot,c);
	}
	cout<<ans-dinic.solve();
	return 0;
}

你可能感兴趣的:(#,最大流)