码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ1497 [NOI2006]最大获利 网络流 最小割 SAP

时间:2018-01-28 14:41:42      阅读:146      评论:0      收藏:0      [点我收藏+]

标签:int   pre   printf   continue   void   ons   scan   std   get   

原文链接http://www.cnblogs.com/zhouzhendong/p/8371052.html


题目传送门 - BZOJ1497


题意概括

  有n个站要被建立。

  建立第i个站的花费为pi。

  特别的,当第Ai和Bi都被建立时可以得到收益Ci.

  问最大收益为多少。


题解

  做法特别巧妙。

  我们假装所有的Ci都可以被取到。

  然后我们考虑至少要失去多少。

  我们对于所有站i,建立S->i的边,边权为Pi.

  对于所有的i,建立Ai->i+n,Bi->i+n边权为INF,以及i+n->T,边权为Ci。

  然后要失去的价值要尽量小,于是我们只需要求得最小割即可。

  由于最小割=最大流,所以SAP跑一跑即可。


代码

#include <cstring>
#include <cstdio>
#include <cstdlib> 
#include <cmath>
#include <algorithm>
using namespace std;
const int N=55005,M=N*3*2,INF=1e9;
struct edge{
	int x,y,cap,flow,nxt;
};
struct gragh{
	int cnt,fst[N],dist[N],n,S,T,num[N],cur[N],p[N];
	int q[N],head,tail;
	edge e[M];
	void set(int _S,int _T,int _n){
		S=_S,T=_T,n=_n,cnt=1;
		memset(fst,0,sizeof fst);
	}
	void add(int a,int b,int c){
		cnt++;
		e[cnt].x=a,e[cnt].y=b,e[cnt].cap=c,e[cnt].flow=0;
		e[cnt].nxt=fst[a],fst[a]=cnt;
		cnt++;
		e[cnt].x=b,e[cnt].y=a,e[cnt].cap=0,e[cnt].flow=0;
		e[cnt].nxt=fst[b],fst[b]=cnt;
	}
	void bfs(){
		memset(dist,-1,sizeof dist);
		head=tail=dist[T]=0;
		q[++tail]=T;
		while (head<tail)
			for (int x=q[++head],y,i=fst[x];i;i=e[i].nxt)
				if ((i&1)&&dist[y=e[i].y]==-1)
					dist[q[++tail]=y]=dist[x]+1;
		for (int i=1;i<=n;i++)
			if (dist[i]==-1)
				dist[i]=n;
	}
	void init(){
		bfs();
		memset(num,0,sizeof num);
		for (int i=1;i<=n;i++)
			num[dist[i]]++,cur[i]=fst[i];
	}
	int Augment(int &x){
		int ex_flow=INF;
		for (int i=T;i!=S;i=e[p[i]].x)
			if (e[p[i]].cap-e[p[i]].flow<=ex_flow)
				ex_flow=e[p[i]].cap-e[p[i]].flow,x=e[p[i]].x;
		for (int i=T;i!=S;i=e[p[i]].x)
			e[p[i]].flow+=ex_flow,e[p[i]^1].flow-=ex_flow;
		return ex_flow;
	}
	int ISAP(){
		int x=S,y,MaxFlow=0;
		init();
		while (dist[S]<n){
			if (x==T){
				MaxFlow+=Augment(x);
				continue;
			}
			bool found=0;
			for (int i=cur[x];i;i=e[i].nxt)
				if (dist[y=e[i].y]+1==dist[x]&&e[i].cap>e[i].flow){
					cur[x]=p[y]=i,x=y,found=1;
					break;
				}
			if (!found){
				int d=n+1;
				for (int i=fst[x];i;i=e[i].nxt)
					if (e[i].cap>e[i].flow)
						d=min(d,dist[e[i].y]+1);
				if (!--num[dist[x]])
					return MaxFlow;
				num[dist[x]=d]++,cur[x]=fst[x],x=x==S?x:e[p[x]].x;
			}
		}
		return MaxFlow;
	}
}g;
int n,m,S,T,p[5005],A[50005],B[50005],C[50005];
int main(){
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
		scanf("%d",&p[i]);
	int total=0;
	for (int i=1;i<=m;i++)
		scanf("%d%d%d",&A[i],&B[i],&C[i]),total+=C[i];
	S=n+m+1,T=n+m+2;
	g.set(S,T,n+m+2);
	for (int i=1;i<=n;i++)
		g.add(S,i,p[i]);
	for (int i=1;i<=m;i++){
		g.add(A[i],i+n,INF);
		g.add(B[i],i+n,INF);
		g.add(i+n,T,C[i]);
	}
	printf("%d",total-g.ISAP());
	return 0;
}

  

BZOJ1497 [NOI2006]最大获利 网络流 最小割 SAP

标签:int   pre   printf   continue   void   ons   scan   std   get   

原文地址:https://www.cnblogs.com/zhouzhendong/p/8371052.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!