题面:
题解:
其实这两道是同一道题。。。。
最小割是用的dinic,不同的最小割是用的isap
其实都是分治求最小割
简单讲讲思路吧
就是首先全部的点都在一个集合里,然后随意定两个点为s和t,这里默认是第一个和最后一个。
然后找到最小割,最小割将整张图分为了s集和t集,于是我们再用这个最小割更新跨集合点对之间的最小割。
这个很好理解,因为当前找到的最小割将s集和t集分开了,显然对于任意一组跨集合的点对而言,当前最小割都是一个可能的最小割。
然后我们再递归处理s集和t集(重复以上步骤)。
每次找到最小割后就更新跨集合点对。
本质上是分治吧。
之前看有些地方提到了最小割树,这里放个链接(这是我找到的写的最全的一篇了)
下面放代码吧,个人觉得看代码会更好理解,尤其是对分治不熟悉的人(比如我)
不同的最小割(isap):
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define R register int 4 #define AC 900 5 #define ac 20000 6 #define inf 2139062143 7 #define D printf("line in %d\n", __LINE__); 8 char READ[7000100], *o = READ; 9 int n, m, s, addflow, t, answer, tt; 10 int last[AC], c[AC], have[AC], a[AC], ans[AC][AC], good[AC]; 11 int Head[AC], date[ac], Next[ac], haveflow[ac], tot = 1; 12 int q[AC], head, tail; 13 int ss[400000], cnt; 14 bool z[AC]; 15 16 inline int read() 17 { 18 int x = 0; char c = getchar(); 19 while(c > '9' || c < '0') c = getchar(); 20 while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); 21 return x; 22 } 23 24 inline void add(int f, int w, int S) 25 { 26 date[++tot] = w, Next[tot] = Head[f], Head[f] = tot, haveflow[tot] = S; 27 date[++tot] = f, Next[tot] = Head[w], Head[w] = tot, haveflow[tot] = S; 28 //printf("%d ---> %d %d\n", f, w, S); 29 } 30 31 inline void upmin(int &a, int b) 32 { 33 if(b < a) a = b; 34 } 35 36 void pre() 37 { 38 int u, v, e; 39 n = read(), m = read(); 40 for(R i = 1; i <= n; i++) a[i] = i; 41 for(R i = 1; i <= m; i++) 42 { 43 u = read(), v = read(), e = read(); 44 add(u, v, e); 45 } 46 memset(ans, 127, sizeof(ans)); 47 } 48 49 bool bfs() 50 { 51 int x, now; 52 memset(have, 0, sizeof(have)); 53 memset(c, 0, sizeof(c)); 54 have[1] = 1, c[t] = 1, x = t; 55 head = tail = 0; 56 q[++tail] = t; 57 while(head < tail) 58 { 59 x = q[++head]; 60 for(R i = Head[x]; i ; i = Next[i]) 61 { 62 now = date[i]; 63 if(haveflow[i] && !c[now]) 64 { 65 c[now] = c[x] + 1; 66 ++have[c[now]];//error...忘记统计了 67 q[++tail] = now; 68 } 69 } 70 } 71 memcpy(good, Head, sizeof(Head)); 72 return c[s]; 73 } 74 75 inline void aru() 76 { 77 int x = t; 78 while(x != s) 79 { 80 haveflow[last[x]] -= addflow; 81 haveflow[last[x] ^ 1] += addflow; 82 x = date[last[x] ^ 1]; 83 } 84 tt += addflow; 85 } 86 87 void isap() 88 { 89 int x = s, now; bool done; 90 tt = 0, addflow = inf; 91 while(c[s] != 875) 92 { 93 if(x == t) aru(), addflow = inf, x = s;//忘记设置全局了,,,那在这里手动改一下吧 94 done = false; 95 for(R i = good[x]; i ; i = Next[i]) 96 { 97 now = date[i]; 98 if(haveflow[i] && c[now] == c[x] - 1) 99 { 100 upmin(addflow, haveflow[i]); 101 done = true; 102 last[now] = i; 103 good[x] = i; 104 x = now; 105 break; 106 } 107 } 108 if(!done) 109 { 110 int go = 874; 111 for(R i=Head[x]; i ; i = Next[i]) 112 { 113 now = date[i]; 114 if(haveflow[i] && c[now]) upmin(go, c[now]); 115 } 116 good[x] = Head[x]; 117 if(!(--have[c[x]])) break; 118 ++have[c[x] = go + 1]; 119 if(x != s) x = date[last[x] ^ 1]; 120 } 121 } 122 } 123 124 void restore()//还原 125 { 126 for(R i = 2; i <= tot; i += 2)//对于无向图而言,这还是非常妙的 127 haveflow[i] = haveflow[i ^ 1] = (haveflow[i] + haveflow[i ^ 1]) / 2; 128 } 129 130 void dfs(int x) 131 { 132 int now; 133 z[x] = true;//.... 134 for(R i = Head[x]; i ; i = Next[i]) 135 { 136 now = date[i]; 137 if(haveflow[i] && !z[now]) dfs(now); 138 } 139 } 140 141 void solve(int l, int r) 142 { 143 if(l == r) return ; 144 s = a[l], t = a[r]; 145 restore(); 146 //printf("%d %d\n", l, r); 147 bfs();//重新定层次 148 isap(); 149 memset(z, 0, sizeof(z)); 150 dfs(s); 151 for(R i=1;i<=n;i++)//更新最小割 152 if(z[i]) 153 for(R j=1;j<=n;j++) 154 if(!z[j]) 155 ans[i][j] = ans[j][i] = min(ans[i][j], tt); 156 int ll = l - 1, rr = r + 1; 157 for(R i = l; i <= r; i++) 158 if(z[a[i]]) q[++ll] = a[i]; 159 else q[--rr] = a[i];//不知道取什么名字了,先借这个用一下吧 160 for(R i = l; i <= r; i++) a[i] = q[i]; 161 solve(l, ll), solve(rr, r); 162 } 163 164 void work() 165 { 166 for(R i=1;i<=n;i++) 167 for(R j=1;j<i;j++) 168 ss[++cnt] = ans[i][j]; 169 sort(ss + 1, ss + cnt + 1); 170 for(R i=1;i<=cnt;i++) 171 if(ss[i] != ss[i + 1]) ++answer; 172 printf("%d\n", answer); 173 } 174 175 int main() 176 { 177 // freopen("in.in","r",stdin); 178 pre(); 179 solve(1, n); 180 work(); 181 // fclose(stdin); 182 return 0; 183 }