题面:

[ZJOI2011]最小割

[CQOI2016]不同的最小割

题解:

其实这两道是同一道题。。。。

最小割是用的dinic,不同的最小割是用的isap

其实都是分治求最小割

简单讲讲思路吧

就是首先全部的点都在一个集合里,然后随意定两个点为s和t,这里默认是第一个和最后一个。

然后找到最小割,最小割将整张图分为了s集和t集,于是我们再用这个最小割更新跨集合点对之间的最小割。

 这个很好理解,因为当前找到的最小割将s集和t集分开了,显然对于任意一组跨集合的点对而言,当前最小割都是一个可能的最小割。

然后我们再递归处理s集和t集(重复以上步骤)。

每次找到最小割后就更新跨集合点对。

本质上是分治吧。

之前看有些地方提到了最小割树,这里放个链接(这是我找到的写的最全的一篇了)

Gomory-Hu tree 最小割树

下面放代码吧,个人觉得看代码会更好理解,尤其是对分治不熟悉的人(比如我)

不同的最小割(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 }
View Code

相关文章:

  • 2022-01-21
  • 2022-12-23
  • 2021-07-01
  • 2021-10-09
  • 2021-12-19
  • 2021-12-23
  • 2021-10-02
  • 2022-12-23
猜你喜欢
  • 2022-03-04
  • 2022-12-23
  • 2022-03-02
  • 2021-09-28
  • 2021-09-07
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案