[学习笔记]最小割树(Gomory-Hu Tree)
最小割树(\(\mathcal{Gomory-Hu Tree}\))简明指南
对于单源最短路径,我们有\(SPFA\)和\(Dijkstra\),对于多源最短路径,我们有\(Floyd\);对于两点间的最小割,我们有\(Dinic\)和\(ISAP\),那么对于多组最小割的询问呢?
这是板子题:
P4897 【模板】最小割树(Gomory-Hu Tree)
这是教程:
首先有一个定理,就是一个\(n\)个点的图上,两点之间只有\(n\)种本质不同的最小割。因此一定存在一棵树,满足树上两点的最小割等于原图上两点的最小割。我们把这样的树称之为“最小割树”。 --Ebola
下面考虑如何建出这样的一棵树。
首先我们在图中随意选取两个点\(u,v\),跑出他们之间的最小割\(cut(u,v)\)。那么满流的边就是图中\(u,v\)之间的割。通过这条割我们把图划分成\(u\)所在的部分和\(v\)所在的部分。把\(u\)所在的那一部分的点集记作\(U\),\(v\)所在的那一部分的点集记作\(V\)。
- 引理:对于任意\(x \in U,y \in V\),有\(cut(x,y) \leq cut(u,v)\)。
- 证明:假设有\(cut(x,y) > cut(u,v)\),那么\(cut(u,v)\)就不能把\(u,v\)割开,因为\(x,y\)依然相连。
那么我们在一张你没有玩过的船新图上在\(u,v\)之间建一条值为\(cut(u,v)\)的边。接下来,我们再分别对\(U,V\)集合进行上述的相同操作,也就是在每一集合中找两个点求最小割,再把集合割开成两个...这样,当我们把原图的点的大集合全部割成一个个点集之后,刚好跑了\(n\)次网络流,建了\(n-1\)条边,也就建成了一棵\(Gomory\)-\(Hu \ Tree\)。
- 引理:对于树上的两点\(u,v\),他们的最小割是他们之间简单路径的最小路径权值。
- 根据上一条引理,显然可得。
那么我们只需要在树上进行查询们就可以得到任意两点的最小割。可以用倍增,也可以用树链剖分。
这是板子:
#include<bits/stdc++.h>
using namespace std;
int n,m,node[505],dep[505],fa[505][10],mn[505][10];
int cnt,top[505],to[1005],len[1005],nex[1005];
int read()
{
int re=0;
char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
return re;
}
void add_edge(int x,int y,int z)
{
to[++cnt]=y,len[cnt]=z,nex[cnt]=top[x],top[x]=cnt;
to[++cnt]=x,len[cnt]=z,nex[cnt]=top[y],top[y]=cnt;
}
namespace GHT
{
int s,t;
int tot,cur[505],dep[505],col[505],col_bucket[505];
int cnt=1,top[505],to[3005],cap[3005],flow[3005],nex[3005];
void add_edge(int x,int y,int z)
{
to[++cnt]=y,cap[cnt]=z,flow[cnt]=0,nex[cnt]=top[x],top[x]=cnt;
to[++cnt]=x,cap[cnt]=z,flow[cnt]=0,nex[cnt]=top[y],top[y]=cnt;
}
bool BFS()
{
memset(cur,0,sizeof cur);
memset(dep,0,sizeof dep);
dep[s]=1,cur[s]=top[s];
queue<int>Q;
Q.push(s);
while(!Q.empty())
{
int now=Q.front();Q.pop();
for(int i=top[now];i;i=nex[i])
if(!dep[to[i]]&&cap[i]>flow[i])
{
dep[to[i]]=dep[now]+1;
cur[to[i]]=top[to[i]];
Q.push(to[i]);
}
}
return dep[t]!=0;
}
int DFS(int now,int rest)
{
if(now==t) return rest;
int re=0;
for(int &i=cur[now];i;i=nex[i])
if(dep[to[i]]==dep[now]+1&&cap[i]>flow[i])
{
int lzq=DFS(to[i],min(rest,cap[i]-flow[i]));
if(lzq)
{
rest-=lzq,re+=lzq;
flow[i]+=lzq,flow[i^1]-=lzq;
if(!rest) break;
}
}
return re;
}
int Dinic(int x,int y)
{
int re=0;s=x,t=y;
for(int i=1;i<=cnt;i++) flow[i]=0;
while(BFS()) re+=DFS(s,0x3f3f3f3f);
return re;
}
void get_color(int now,int color)
{
col[now]=color;
for(int i=top[now];i;i=nex[i])
if(cap[i]>flow[i]&&col[to[i]]!=color)
get_color(to[i],color);
}
void build(int l,int r)
{
if(l==r) return ;
int x=node[l],y=node[l+1];
int cut=Dinic(x,y);
get_color(x,++tot);
int L=l,R=r;
for(int i=l;i<=r;i++)
if(col[node[i]]==tot) col_bucket[L++]=node[i];
else col_bucket[R--]=node[i];
for(int i=l;i<=r;i++) node[i]=col_bucket[i];
::add_edge(x,y,cut);
build(l,L-1);
build(R+1,r);
}
}
void dfs(int now)
{
for(int i=1;i<=9;i++)
{
fa[now][i]=fa[fa[now][i-1]][i-1];
mn[now][i]=min(mn[now][i-1],mn[fa[now][i-1]][i-1]);
}
for(int i=top[now];i;i=nex[i])
{
if(to[i]==fa[now][0]) continue;
dep[to[i]]=dep[now]+1,fa[to[i]][0]=now,mn[to[i]][0]=len[i];
dfs(to[i]);
}
}
int getcut(int x,int y)
{
int re=INT_MAX;
if(dep[x]<dep[y]) swap(x,y);
for(int i=9;i>=0;i--) if(dep[fa[x][i]]>=dep[y]) re=min(re,mn[x][i]),x=fa[x][i];
if(x==y) return re;
for(int i=9;i>=0;i--) if(fa[x][i]!=fa[y][i]) re=min(re,min(mn[x][i],mn[y][i])),x=fa[x][i],y=fa[y][i];
return min(re,min(mn[x][0],mn[y][0]));
}
int main()
{
n=read(),m=read();
while(m--)
{
int x=read(),y=read(),z=read();
GHT::add_edge(x,y,z);
}
for(int i=1;i<=n;i++) node[i]=i;
GHT::build(1,n);
dep[1]=1;
dfs(1);
m=read();
while(m--)
{
int x=read(),y=read();
printf("%d\n",getcut(x,y));
}
return 0;
}
[学习笔记]最小割树(Gomory-Hu Tree)的更多相关文章
- 最小割树Gomory–Hu tree
fanhq666地址:http://fanhq666.blog.163.com/blog/static/8194342620113495335724/ wiki地址(证明):https://en.wi ...
- bzoj 4519: [Cqoi2016]不同的最小割【最小割树Gomory–Hu tree】
算法详见:http://www.cnblogs.com/lokiii/p/8191573.html 求出点两两之间的最小割之后,把他们扔到map/set里跑即可 可怕的是map和set跑的时间竟然完全 ...
- bzoj 2229: [Zjoi2011]最小割【Gomory–Hu tree最小割树】
这个算法详见http://www.cnblogs.com/lokiii/p/8191573.html 求出两两之间最小割之后暴力统计即可 #include<iostream> #inclu ...
- 【模板】最小割树(Gomory-Hu Tree)
传送门 Description 给定一个\(n\)个点\(m\)条边的无向连通图,多次询问两点之间的最小割 两点间的最小割是这样定义的:原图的每条边有一个割断它的代价,你需要用最小的代价使得这两个点不 ...
- [学习笔记]最小割之最小点权覆盖&&最大点权独立集
最小点权覆盖 给出一个二分图,每个点有一个非负点权 要求选出一些点构成一个覆盖,问点权最小是多少 建模: S到左部点,容量为点权 右部点到T,容量为点权 左部点到右部点的边,容量inf 求最小割即可. ...
- 最小割树(Gomory-Hu Tree)
当我们遇到这样的问题: 给定一个 \(n\) 个点 \(m\) 条边的无向连通图,多次询问两点之间的最小割 我们通常要用到最小割树. 博客 建树 分治.记录当前点集,然后随便找俩点当 \(s\) 和 ...
- LoibreOJ 2042. 「CQOI2016」不同的最小割 最小割树 Gomory-Hu tree
2042. 「CQOI2016」不同的最小割 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 ...
- 最小割树(Gomory-Hu Tree)求无向图最小割详解 附 BZOJ2229,BZOJ4519题解
最小割树(Gomory-Hu Tree) 前置知识 Gomory-Hu Tree是用来解决无向图最小割的问题的,所以我们需要了解无向图最小割的定义 和有向图类似,无向图上两点(x,y)的割定义为一个边 ...
- [模板]最小割树(Gomory-Hu Tree)(luogu4897)
给定一个\(n\)个点\(m\)条边的无向连通图,多次询问两点之间的最小割 两点间的最小割是这样定义的:原图的每条边有一个割断它的代价,你需要用最小的代价使得这两个点不连通 Input 第一行两个数\ ...
随机推荐
- springboot整合jsp 遇到的问题
1,在idea中新建jsp文件 首先需要在springboot项目 在src 中webapp /WEB-INF/JSP 当我右键想新建一个jsp文件时默认没有 File->Project Str ...
- WPF 动态添加控件以及样式字典的引用(Style introduction)
原文:WPF 动态添加控件以及样式字典的引用(Style introduction) 我们想要达到的结果是,绑定多个Checkbox然后我们还可以获取它是否被选中,其实很简单,我们只要找到那几个关键的 ...
- python图像、视频转字符画
python图像转字符画需要用到matplotlib.pyplot库,视频转字符画需要用到opencv库,这里的代码基于python 3.5 图像转字符画需要先将图像转为灰度图,转灰度图的公式是 gr ...
- Redis 布隆过滤器
1.布隆过滤器 内容参考:https://www.jianshu.com/p/2104d11ee0a2 1.数据结构 布隆过滤器是一个BIT数组,本质上是一个数据,所以可以根据下标快速找数据 2.哈希 ...
- Oracle使用存储过程返回查询游标
如果报表逻辑非常复杂的话, 可以把报表逻辑放到存储过程里,加工一个全局临时表.前端查询的时候只查询临时表即可.只是第一次查询需要忍受加工的时间. --创建存储过程,返回SYS_REFCURSOR CR ...
- 微信小程序の模板
一.什么是模板 模板顾名思义就是可以复用的代码块.减少编码工作量. 二.例子 <template name="templateTest"> <view>th ...
- 2019-9-2-C#委托
title author date CreateTime categories C#委托 lindexi 2019-09-02 12:57:37 +0800 2018-2-13 17:23:3 +08 ...
- C#多线程的应用
1.进程 就像我们任务管理器里面运行的进程 进程(Process)是Windows系统中的一个基本概念,它包含着一个运行程序所需要的资源.一个正在运行的应用程序在操作系统中被视为一个进程,进程可以包括 ...
- 初撩Django-RESTful-rest_framework视图函数
rest_framework中的视图函数: View函数 APIView函数 APIView的子类 mixins函数 viewsets函数 1.View函数 2.APIView函数 3.APIView ...
- mysql的数据导出方法
mysql的数据导出几种方法 从网上找到一些问题是关于如何从MySQL中导出数据,以便用在本地或其它的数据库系统之上:以及 将现有数据导入MySQL数据库中. 数据导出 数据导出主要有以下几种方法 ...