最小割树
考试考了,发现自己不会,所以写一下。
最小割树(Gomory−HuTree) 为一颗有 \(n\) 个点的带边权树,满足对于任意两点 \((u,v)\) ,满足其在树上的瓶颈路为原图中两点之间的最小割(最大流)。
建立方法如下:
-
在点集 \(S\) (初始时为1~n) 中取两点 \(s,t\) ,计算其原图上最小割(最大流),记为 \(cut(s,t)\)。
-
找到包含 \(s\) 的割集(残量网络中的连通分量)\(U\) ,包含 \(t\) 的割集 \(V\)。
-
在树上加入一条 \((u,v)\) 之间的边,边权为 \(cut(s,t)\)
-
对点集 \(U\) , \(V\) 递归的进行操作
这样来看,总共会做 \(n-1\) 次最小割,复杂度为 \(O(n^3m)\) 。不过由于 Dinic 算法特殊的复杂度,遇到问题时一般要特殊分析。
下面我们要证明这个过程是对的,也就是说对于 \(s\) 在 \((s,t)\) 割中所在的割集 \(W\) ,\(u,v \in W\) ,\(X\) 是 \((u,v)\) 割中 \(u\) 所在的割集,证明存在一种割的方式使得 \(X \subset W\)
定义 \(c(x)\) 表示所有仅有一个端点在 \(x\) 中的边权和,可以观察到有若干性质:
情况1: \(t \not \in X\)
由于 \(c(X)+c(W) \geq c(X \cup W) + c(X \cap W)\)
\(c(X \cup W)\) 是一个 \((s,t)\) 割,所以 \(c(X \cup W) \geq c(W)\)
\(c(X \cap W)\) 是一个 \((u,v)\) 割,所以 \(c(X \cap W) \geq c(X)\)
所以 \(c(X \cap W) = c(X)\)
情况2: \(t \in X\)
由于 \(c(X)+c(W) \geq c(X \setminus W) + c(W \setminus X)\)
\(c(X \setminus W)\) 是一个 \((s,t)\) 割,所以 \(c(X \setminus W) \geq c(W)\)
\(c(W \setminus X)\) 是一个 \((u,v)\) 割,所以 \(c(W \setminus X) \geq c(X)\)
所以 \(c(W \setminus X) = c(X)\)
宗上,总是有一种方法满足 \(X \subset W\)
同时,我们也证明了对于一个 \(n\) 的图,会有 \(n-1\) 中值不同的最小割。
应用:
多次求最大流(最小割)
建最小割树,然后转化成树上的路径 \(\min\) ,就能直接维护。
模板:
void mark(int x){
//cout<<x<<endl;
vis[x]=true;
for(int i=head[x];i!=-1;i=edge[i].nxt){
int to=edge[i].to;
if(edge[i].cap>edge[i].flow&&!vis[to]){
mark(to);
}
}
}
void solve(vector<int > S){
if(S.size()==1)return;
tNode=0;
for(int i=1;i<=n;i++)head[i]=-1;
for(int i=0;i<nedge.size();i++){
cedge cur=nedge[i];
addE(cur.u,cur.v,cur.c);
addE(cur.v,cur.u,0);
}
s=S[0];
t=S[1];
int cut=DINIC();
sum+=cut;
tree[s].push_back(mk(cut,t));
tree[t].push_back(mk(cut,s));
memset(vis,false,sizeof(vis));
mark(s);
vector<int > U,M;
for(int i=0;i<S.size();i++){
if(vis[S[i]])U.push_back(S[i]);
else M.push_back(S[i]);
}
solve(U);
solve(M);
}
题解一会写
记得补充图片

浙公网安备 33010602011771号