BZOJ1497: [NOI2006]最大获利

来源:互联网 发布:python 分割文件 编辑:程序博客网 时间:2024/04/29 14:13
什么是最大权闭合子图:
先解释一下有向图的闭合图:闭合图内任意点的任意后继也一定还在闭合图中。
物理意义:事物间依赖关系:一个事件要发生,它需要的所有前提也都一定要发生。
最大权闭合图:点权之和最大的闭合图


最大权闭合图构图方法:
1.增加源s汇t 
2.源s连接原图的正权点,容量为相应点权
3.原图的负权点连接汇t,容量为相应点权的相反数
4.原图边的容量为正无限. 


最大权闭合图 解决:
闭合图V的权为正权点总和减去对应割的容量
当割最小时,闭合图权最大


NOI2006 最大获利:
1.将原题中的边和点都看成事件。
2.边事件依赖边的两个端点事件的发生。这与闭合图的性质相似。
3.构造性地,将边转化为点事件。
4.将所有边都转化为事件点,原图便转化为一个二分图。

5.解决该二分图的最大权闭合图即可

#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int N=120005;const int M=400005;const int inf=2100000000;int n,m,S,T;int from[M],to[M],nxt[M],w[M],lj[N],cnt=-1;void insert(int f,int t,int p){to[++cnt]=t;nxt[cnt]=lj[f];lj[f]=cnt;w[cnt]=p;to[++cnt]=f;nxt[cnt]=lj[t];lj[t]=cnt;w[cnt]=0;}int d[N],q[N*2];bool bfs(){memset(d,0,sizeof(d));int h=1,t=1,x,j;q[1]=S,d[S]=1;while(h!=t+1){x=q[h];for(int i=lj[x];i>=0;i=nxt[i])if(w[i]&&!d[to[i]]){d[to[i]]=d[x]+1;q[++t]=to[i];if(t==N) t=0;}if(++h==N) h=0;}if(d[T]) return true;return false; }int dfs(int x,int v){if(x==T||v==0) return v;int f,ret=0;for(int i=lj[x];i>=0;i=nxt[i])if(d[to[i]]==d[x]+1){f=dfs(to[i],min(w[i],v));w[i]-=f;w[i^1]+=f;v-=f;ret+=f;if(v==0) break;}return ret;}int main(){scanf("%d%d",&n,&m);T=m+n+1,S=0;int x,y,p;for(int i=0;i<=T;i++) lj[i]=-1;for(int i=1;i<=n;i++){scanf("%d",&x);insert(0,i,x);}int sum=0,ans=0;for(int i=1;i<=m;i++){scanf("%d%d%d",&x,&y,&p);insert(n+i,T,p);insert(x,n+i,inf);insert(y,n+i,inf);sum+=p;}while(bfs()) ans+=dfs(S,inf);printf("%d",sum-ans);}


0 0