Amber的论文《最小割模型在信息学竞赛中的应用》
【最大权闭合图】定义一个有向图G=(V,E)的闭合图,是该有向图的一个点集,且该点集所有出边都还指向该点集。即闭合图内的任意点的任意后继也一定在闭合图中。
【建图】源点向正权点加边,容量为权值;负权点向汇点加边,容量为权的绝对值;有限制关系的点加边,容量为INF。
【定理】最大权闭合图 = 正权值和 - 最小割
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<stdio.h> 2 #include<string.h> 3 #include<math.h> 4 #include<algorithm> 5 6 using namespace std; 7 8 #define INF 1e8 9 #define MAX_VECT 505 10 #define MAX_EDGE 220000 11 12 /************************************************************************/ 13 /* Name: dinic 14 /* Description: Find the max flow of the network from start to 15 end point 16 /* Variable Description: to[] - end point of the current edge 17 next[] - the next edge which also comes from 18 the same point as current edge 19 cap[] - the capability of the current edge 20 v[] - the first edge index which comes from the 21 the current point 22 d[] - the layer number of current point 23 /************************************************************************/ 24 25 26 int to[MAX_EDGE], next[MAX_EDGE], cap[MAX_EDGE], tot; 27 int v[MAX_VECT], d[MAX_VECT], queue[MAX_VECT], n; 28 int S, T; 29 inline void single_insert(int _u, int _v, int var) 30 { 31 to[tot] = _v; 32 cap[tot] = var; 33 next[tot] = v[_u]; 34 v[_u] = tot++; 35 } 36 37 void insert(int from, int to, int cap) 38 { 39 single_insert(from, to, cap); 40 single_insert(to, from, 0); 41 } 42 43 bool bfs_initial() 44 { 45 memset(d, -1, sizeof(d)); 46 int bg, ed, x, y; 47 bg = ed = d[S] = 0; 48 queue[ed++] = S; 49 while (bg < ed) 50 { 51 x = queue[bg++]; 52 for (int i = v[x]; i+1; i = next[i]) 53 { 54 y = to[i]; 55 if (cap[i] && d[y] == -1) 56 { 57 d[y] = d[x] + 1; 58 if (y == T) return true; 59 queue[ed++] = y; 60 } 61 } 62 } 63 return false; 64 } 65 66 int Find(int x, int low = INF) 67 { 68 if (x == T) return low; 69 int ret, y, ans = 0; 70 for (int i = v[x]; (i+1) && low; i = next[i]) 71 { 72 y = to[i]; 73 if (cap[i] && d[y] == d[x] + 1 && (ret = Find(y, min(low, cap[i])))) 74 { 75 cap[i] -= ret; 76 cap[i^1] += ret; 77 low -= ret; 78 ans += ret; 79 } 80 } 81 return ans; 82 } 83 int dinic() 84 { 85 int ans = 0; 86 while (bfs_initial()) 87 ans += Find(S); 88 return ans; 89 } 90 91 92 int dinicc() 93 { 94 int ans = 0; 95 while(bfs_initial()) 96 { 97 int edge, x, y, back, iter = 1; 98 while(iter) 99 { 100 x = (iter == 1) ? S : to[queue[iter - 1]]; 101 if (x == T) 102 { 103 int minE, minCap = INF; 104 for (int i = 1; i < iter; i++) 105 { 106 edge = queue[i]; 107 if (cap[edge] < minCap) 108 { 109 minCap = cap[edge]; 110 back = i; 111 } 112 } 113 for (int i = 1; i < iter; i++) 114 { 115 edge = queue[i]; 116 cap[edge] -= minCap; 117 cap[edge ^ 1] += minCap; 118 } 119 ans += minCap; 120 iter = back; 121 } 122 else 123 { 124 for (edge = v[x]; edge + 1; edge = next[edge]) 125 { 126 y = to[edge]; 127 if (cap[edge] && d[y] == d[x] + 1) 128 break; 129 } 130 if (edge+1) 131 queue[iter++] = edge; 132 else 133 { 134 d[x] = -1; 135 iter--; 136 } 137 } 138 } 139 } 140 return ans; 141 } 142 int m; 143 int seq[MAX_VECT]; 144 int main() 145 { 146 while (scanf("%d%d",&n,&m)==2) 147 { 148 tot = 0; 149 memset(v,-1,sizeof(v)); 150 int sum = 0; 151 S = 0; 152 T = n+1; 153 for (int i=1;i<=n;i++) 154 { 155 scanf("%d",&seq[i]); 156 if (seq[i] > 0){ 157 sum += seq[i]; 158 insert(S,i,seq[i]); 159 }else{ 160 insert(i,T,-seq[i]); 161 } 162 } 163 for (int i=1;i<=m;i++) 164 { 165 int u,v; 166 scanf("%d%d",&u,&v); 167 insert(u,v,INF); 168 } 169 170 int ans = sum - dinic(); 171 printf("%d\n",ans); 172 } 173 return 0; 174 }