码迷,mamicode.com
首页 > 其他好文 > 详细

最小割学习小结

时间:2015-12-19 15:05:26      阅读:243      评论:0      收藏:0      [点我收藏+]

标签:

一直对最小割模型的理解不够深刻,这段时间学习、总结了一下。

【强烈推荐胡伯涛和彭天翼的论文】

 

总结几点:

(1)跑完一遍S-T最大流后,在最小割[S,T]中的边必定都是满流的边,但满流的边不一定都是最小割中的边。

(2)最小割的任意方案:跑一遍S-T最大流,然后在残余网络中S能够达到的点为一个割集,剩下的点为另一个割集。

(3)最小割方案的唯一性:跑一遍S-T最大流,如果在残余网络中任意一个点都能从S或者T出发达到,那么最小割方案有唯一性;否则没有唯一性。

(4)跑一遍S-T最大流后,残余网络中所有S能够达到的点必定在S割集中;残余网络中所有T能够达到的点必定在T割集中。

(5)跑一遍S-T最大流后。满足:

若边(u,v)满流,且删掉该边后在残余网络中找不到u到v的路径,则(u,v)可能出现在某个最小割方案中。

若边(u,v)满流,且在残余网络中s能够达到u,v能够达到t,则(u,v)必定出现在任意一个最小割方案中。

 

例题:

BZOJ 1797 [Ahoi2009]Mincut 最小割

这道题就是上面第(5)点的一个直接应用。那么如何判断某条边是否满足那两个条件呢?

跑完最大流后,在残余网络中求一遍强连通分量。对于某条满流的边(u,v),若u和v不在同一个强连通分量中,则满足第一个条件。若u和S在同一个强连通分量中且v和T在同一个强连通分量中,则满足第二个条件。

技术分享
  1 #include <stack>
  2 #include <queue>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <algorithm>
  6 
  7 using namespace std;
  8 
  9 const size_t Max_N(4050);
 10 const size_t Max_M(120050);
 11 const int INF(0X7F7F7F7F);
 12 
 13 size_t N;
 14 size_t S, T;
 15 
 16 unsigned int Total;
 17 unsigned int Head[Max_N];
 18 unsigned int From[Max_M], To[Max_M], Next[Max_M];
 19 int Cap[Max_M], Flow[Max_M];
 20 
 21 stack<size_t> SV;
 22 unsigned int DFS_Clock;
 23 unsigned int Pre[Max_N], Low_Link[Max_N];
 24 unsigned int SCC_Total;
 25 unsigned int SCC_Number[Max_N];
 26 
 27 void Get_Val(unsigned int &ret)
 28 {
 29     ret = 0;
 30     char ch;
 31     while ((ch = getchar()), (ch > 9 || ch < 0))
 32         ;
 33     do
 34     {
 35         (ret *= 10) += ch - 0;
 36     }
 37     while ((ch = getchar()), (ch >= 0 && ch <= 9));
 38 }
 39 
 40 void Get_Val(int &ret)
 41 {
 42     ret = 0;
 43     char ch;
 44     while ((ch = getchar()), (ch > 9 || ch < 0))
 45         ;
 46     do
 47     {
 48         (ret *= 10) += ch - 0;
 49     }
 50     while ((ch = getchar()), (ch >= 0 && ch <= 9));
 51 }
 52 
 53 inline
 54 void Add_Edge(const size_t &tot, const size_t &s, const size_t &t, const int &c)
 55 {
 56     From[tot] = s, To[tot] = t;
 57     Cap[tot] = c, Flow[tot] = 0;
 58     Next[tot] = Head[s], Head[s] = tot;
 59 }
 60 
 61 void init()
 62 {
 63     unsigned int M;
 64     size_t u, v;
 65     int c;
 66     
 67     Get_Val(N), Get_Val(M);
 68     Get_Val(S), Get_Val(T);
 69     while (M--)
 70     {
 71         Get_Val(u), Get_Val(v), Get_Val(c);
 72         Total += 2;
 73         Add_Edge(Total, u, v, c);
 74         Add_Edge(Total ^ 1, v, u, 0);
 75     }
 76 }
 77 
 78 size_t Cur[Max_N];
 79 unsigned int Dist[Max_N];
 80 bool BFS()
 81 {
 82     memset(Dist, 0, sizeof(Dist));
 83     queue<size_t> Q;
 84     Q.push(S);
 85     Dist[S] = 1;
 86     size_t Top;
 87     
 88     while (Q.size())
 89     {
 90         Top = Q.front();
 91         Q.pop();
 92         for (size_t i = Head[Top];i;i = Next[i])
 93             if (!Dist[To[i]] && Cap[i] > Flow[i])
 94             {
 95                 Dist[To[i]] = Dist[Top] + 1;
 96                 Q.push(To[i]);
 97             }
 98     }
 99     
100     return Dist[T];
101 }
102 
103 int DFS(const size_t &u, int a)
104 {
105     if (u == T || a == 0)
106         return a;
107     int Ans(0), f;
108     for (size_t &i = Cur[u];i;i = Next[i])
109         if (Dist[To[i]] == Dist[u] + 1)
110             if ((f = DFS(To[i], min(a, Cap[i] - Flow[i]))) > 0)
111             {
112                 Ans += f;
113                 a -= f;
114                 Flow[i] += f;
115                 Flow[i ^ 1] -= f;
116                 if (a == 0)
117                     break;
118             }
119     return Ans;
120 }
121 
122 void Dinic()
123 {
124     while (BFS())
125     {
126         for (size_t i = 1;i <= N;++i)
127             Cur[i] = Head[i];
128         DFS(S, INF);
129     }
130 }
131 
132 void Tarjan(const size_t &u)
133 {
134     Pre[u] = Low_Link[u] = ++DFS_Clock;
135     SV.push(u);
136     
137     size_t v;
138     for (size_t i = Head[u];i;i = Next[i])
139         if (Cap[i] > Flow[i])
140         {
141             v = To[i];
142             if (!Pre[v])
143             {
144                 Tarjan(v);
145                 Low_Link[u] = min(Low_Link[u], Low_Link[v]);
146             }
147             else
148                 if (!SCC_Number[v])
149                     Low_Link[u] = min(Low_Link[u], Pre[v]);
150         }
151     
152     if (Pre[u] == Low_Link[u])
153     {
154         ++SCC_Total;
155         while (true)
156         {
157             v = SV.top();
158             SV.pop();
159             SCC_Number[v] = SCC_Total;
160             if (u == v)
161                 break;
162         }
163     }
164 }
165 
166 int main()
167 {
168     init();
169     
170     Dinic();
171     
172     for (size_t i = 1;i <= N;++i)
173         if (!Pre[i])
174             Tarjan(i);
175     
176     for (size_t i = 2;To[i];i += 2)
177     {
178         unsigned int u = From[i], v = To[i];
179         if (Cap[i] == Flow[i] && SCC_Number[u] != SCC_Number[v])
180             printf("1 ");
181         else
182             printf("0 ");
183         if (Cap[i] == Flow[i] && SCC_Number[u] == SCC_Number[S] && SCC_Number[v] == SCC_Number[T])
184             printf("1");
185         else
186             printf("0");
187         if (To[i + 2])
188             printf("\n");
189     }
190     
191     return 0;
192 }
BZOJ 1797

 

未完待续。

 

最小割学习小结

标签:

原文地址:http://www.cnblogs.com/Created-equal/p/5059028.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!