TYVJ 1452 最大权闭合图
若有向图G的子图V满足【V中顶点的所有出边均指向V内部顶点】,则称V是G的一个闭合子图。其中点权和最大的闭合子图称为有向图G的最大权闭合子图,简称最大权闭合图。
最大权闭合图的构图方法如下:建立源点S和汇点T,源点S连所有点权为正的点,容量为该点点权;其余点连汇点T,容量为点权绝对值,对于原图中的边<u,v>,连边<u,v>,容量+∞。
定理1:最大权闭合图的点权和 = 所有正权点权值和 - 最小割(最大流)。
定理2:上述网络的最小割包含:S到“不在最大权闭合图内的正权节点”的边 以及 “在最大权闭合图内的负权节点”到T的边。
定理2的推论:在残余网络中由源点S能够访问到的点,就构成一个点数最少的最大权闭合图。
以上引自:lyd神犇的博客~http://hi.baidu.com/lydrainbowcat/item/ee01570b259f17cc75cd3c65
以备自己复习时候看~
应用拓扑排序消环~
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdlib> 4 #include <cstdio> 5 #include <cstring> 6 //先去环再去反向边,不能先建反边再去环 7 #define N 10010 8 #define M 2000100 9 #define INF 1e9 10 11 using namespace std; 12 13 int head[N],to[M],next[M],len[M]; 14 int pto[M],phead[N],pnext[M],pin[N],pout[N],val[N]; 15 int q[M*5],layer[N]; 16 bool vis[N]; 17 int n,cnt,pcnt,S,T,sum; 18 19 inline void padd(int u,int v) 20 { 21 pto[pcnt]=v; pnext[pcnt]=phead[u]; phead[u]=pcnt++; 22 pin[v]++; 23 } 24 25 inline void add(int u,int v,int w) 26 { 27 to[cnt]=v; len[cnt]=w; next[cnt]=head[u]; head[u]=cnt++; 28 to[cnt]=u; len[cnt]=0; next[cnt]=head[v]; head[v]=cnt++; 29 } 30 31 inline void topsort() 32 { 33 int h=1,t=1,sta; 34 for(int i=1;i<=n;i++) 35 if(pin[i]==0) q[t++]=i; 36 while(h<t) 37 { 38 sta=q[h++]; 39 for(int i=phead[sta];~i;i=pnext[i]) 40 { 41 pin[pto[i]]--; 42 if(pin[pto[i]]==0) q[t++]=pto[i]; 43 } 44 } 45 for(int i=1;i<t;i++) vis[q[i]]=true; 46 } 47 48 inline void read() 49 { 50 memset(head,-1,sizeof head); cnt=0; 51 memset(phead,-1,sizeof phead); pcnt=0; 52 scanf("%d",&n); 53 S=0; T=n+1; 54 for(int i=1;i<=n;i++) 55 { 56 scanf("%d%d",&val[i],&pout[i]); 57 for(int j=1,a;j<=pout[i];j++) 58 { 59 scanf("%d",&a); 60 padd(a,i); 61 } 62 } 63 topsort(); 64 for(int i=1;i<=n;i++) 65 if(vis[i]) 66 { 67 if(val[i]<0) add(i,T,-val[i]); 68 else add(S,i,val[i]),sum+=val[i]; 69 for(int j=phead[i];~j;j=pnext[j]) 70 if(vis[pto[j]]) add(pto[j],i,INF); 71 } 72 } 73 74 inline bool bfs() 75 { 76 memset(layer,-1,sizeof layer); 77 int h=1,t=2,sta; 78 q[1]=S; layer[S]=0; 79 while(h<t) 80 { 81 sta=q[h++]; 82 for(int i=head[sta];~i;i=next[i]) 83 if(len[i]&&layer[to[i]]<0) 84 { 85 layer[to[i]]=layer[sta]+1; 86 q[t++]=to[i]; 87 } 88 } 89 return layer[T]!=-1; 90 } 91 92 inline int find(int u,int cur_flow) 93 { 94 if(u==T) return cur_flow; 95 int res=0,tmp; 96 for(int i=head[u];~i&&res<cur_flow;i=next[i]) 97 if(len[i]&&layer[to[i]]==layer[u]+1) 98 { 99 tmp=find(to[i],min(cur_flow-res,len[i])); 100 len[i]-=tmp; len[i^1]+=tmp; res+=tmp; 101 } 102 if(!res) layer[u]=-1; 103 return res; 104 } 105 106 inline void go() 107 { 108 int ans=0; 109 while(bfs()) ans+=find(S,INF); 110 printf("%d\n",sum-ans); 111 } 112 113 int main() 114 { 115 read(); 116 go(); 117 return 0; 118 }
没有人能阻止我前进的步伐,除了我自己!