链接1

链接2

题意简述

第一个题 : 问图中有多少不同的最小割数值

第二个题 : \(q\) 次询问图中多少对点对之间的最小割小于 \(x\) 。

Sol

两个都是模板题就放一起了。

求完最小割树直接暴力 \(O(n^2)\) 弄出所有点对间最小割 , 然后该干嘛干嘛。


最小割树的构建:

\(Gemory-Hu\; Tree\)算法

对于一个 \(n\) 个节点的图 , 图中所有点对不同的最小割数目最多只有 \(n-1\) 个 , 可以证明存在一棵树 , 使得两点在这棵树上的最小割即为原图中的最小割 。

考虑3个点两两之间的最小割 \(C_{u,v},C_{u,t},C_{v,t}\) , 我们已知 \(C_{u,t},C_{v,t}\) , 假设在\(C_{u,v}\)中 ,不妨假设 \(t\) 被分在了与 \(v\) 在一起的割集 。由于在一个割中一个点一定被分在源点或者汇点的一侧割集 , 那么可以推出 \(C_{u,v}\leq C_{u,t}\) , 如果不是那么显然直接割掉 \(u,t\) 就能达到割掉 \(u,v\) 的目的而使最小割变小。

类似的可以得出 \(C_{u,v}\geq C_{u,t}\) , 那么只能是 \(C_{u,v}=C_{u,t}\) 。

用归纳法可以得到一个 \(n\) 个点的图中最多只有 \(n-1\) 个不同的最小割。

如何构建最小割树?

采用递归的策略 , 对于当前点集 , 任意取两个点做最小割(注意这里是对原图跑最小割) , 然后给这两个点连边 , 权值为最小割大小。

然后就把参与网络中与源点可达的点与源点扔在一起 , 与其他的和汇点扔在一起。两边递归即可。

正确性就是证明只有 \(n-1\) 个不同的最小割中的道理相同 , 考虑某一个点被划分在哪个集合从而保证了正确性。

代码:

cpp1:

#include<bits/stdc++.h>
using namespace std;
#define Set(a,b) memset(a,b,sizeof(a))
#define Copy(a,b) memcpy(a,b,sizeof(a))
template<class T> inline void init(T&x){
x=0;char ch=getchar();bool t=0;
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
if(t) x=-x;
}
const int M=3020;
const int N=200;
const int INF=2e9;
struct edge{
int to,next,cap,flow;
}a[M<<1];
int head[N],cnt=0;
int que[N],n,m;
inline void add(int x,int y,int z){a[cnt]=(edge){y,head[x],z,z};head[x]=cnt++;}
int d[N],S,T,cur[N];
bool bel[N];queue<int> Q;
inline bool bfs(){
while(!Q.empty())Q.pop();
Set(d,0);d[S]=1;Q.push(S);
while(!Q.empty()){
int u=Q.front();Q.pop();
for(int v,i=head[u];~i;i=a[i].next){
v=a[i].to;if(d[v]||!a[i].cap) continue;
d[v]=d[u]+1;if(v==T) return 1;
Q.push(v);
}
}
return d[T];
}
int dfs(int u,int flow){
if(u==T) return flow;
int rest=flow;
for(int v,&i=cur[u];~i;i=a[i].next){
v=a[i].to;if(!a[i].cap||d[v]!=d[u]+1) continue;
int f=dfs(v,min(a[i].cap,rest));
if(!f) d[v]=0;
rest-=f;a[i].cap-=f,a[i^1].cap+=f;
if(!rest) break;
}
return flow-rest;
}
inline int Dinic(){
int flow=0;
while(bfs()) Copy(cur,head),flow+=dfs(S,INF);
return flow;
}
inline void Return(){for(int i=0;i<cnt;++i) a[i].cap=a[i].flow;for(int i=1;i<=n;++i) bel[i]=0;}
void Dfs(int u){bel[u]=1;for(int v,i=head[u];~i;i=a[i].next){v=a[i].to;if(a[i].cap&&!bel[v]) Dfs(v);}}
namespace GHT{
struct edge{int to,next,w;}a[N<<1];
int head[N],cnt=0;
inline void add(int x,int y,int z){a[++cnt]=(edge){y,head[x],z};head[x]=cnt;}
int tmp[N];
inline void Clear(){Set(head,0);cnt=0;}
void Build(int l,int r){
if(l>=r) return;
S=que[l],T=que[r];Return();int Flow=Dinic();Dfs(S);
int L=l-1,R=r+1;add(S,T,Flow),add(T,S,Flow);
for(int i=l;i<=r;++i) {int u=que[i];if(bel[u]) tmp[++L]=u;else tmp[--R]=u;}
for(int i=l;i<=r;++i) que[i]=tmp[i];
Build(l,L),Build(R,r);
return;
}
int gezi[N*N];
inline void DFS(int u,int fa,int Mi){
if(Mi!=INF) gezi[++gezi[0]]=Mi;
for(int v,i=head[u];i;i=a[i].next){
v=a[i].to;if(v==fa) continue;
DFS(v,u,min(Mi,a[i].w));
}
}
inline void work(){
for(int i=1;i<=n;++i) que[i]=i;
Build(1,n);gezi[0]=0;
for(int i=1;i<=n;++i) DFS(i,0,INF);
sort(gezi+1,gezi+1+gezi[0]);
int q;init(q);
while(q--){
int x;init(x);printf("%d\n",(upper_bound(gezi+1,gezi+1+gezi[0],x)-gezi-1)/2);
}
puts("");
return;
}
}
int main()
{
int T;init(T);
while(T--){
Set(head,-1);cnt=0;GHT::Clear();
init(n),init(m);
int u,v,w;
for(int i=1;i<=m;++i) {
init(u),init(v),init(w);
add(u,v,w),add(v,u,w);
}
GHT::work();
}
return 0;
}

cpp2:

#include<bits/stdc++.h>
using namespace std;
#define Set(a,b) memset(a,b,sizeof(a))
#define Copy(a,b) memcpy(a,b,sizeof(a))
template<class T> inline void init(T&x){
x=0;char ch=getchar();bool t=0;
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
if(t) x=-x;
}
const int M=8501;
const int N=1000;
const int INF=2e9;
struct edge{
int to,next,cap,flow;
}a[M<<1];
int head[N],cnt=0;
int que[N],n,m;
inline void add(int x,int y,int z){a[cnt]=(edge){y,head[x],z,z};head[x]=cnt++;}
int d[N],S,T,cur[N];
bool bel[N];queue<int> Q;
inline bool bfs(){
while(!Q.empty())Q.pop();
Set(d,0);d[S]=1;Q.push(S);
while(!Q.empty()){
int u=Q.front();Q.pop();
for(int v,i=head[u];~i;i=a[i].next){
v=a[i].to;if(d[v]||!a[i].cap) continue;
d[v]=d[u]+1;if(v==T) return 1;
Q.push(v);
}
}
return d[T];
}
int dfs(int u,int flow){
if(u==T) return flow;
int rest=flow;
for(int v,&i=cur[u];~i;i=a[i].next){
v=a[i].to;if(!a[i].cap||d[v]!=d[u]+1) continue;
int f=dfs(v,min(a[i].cap,rest));
if(!f) d[v]=0;
rest-=f;a[i].cap-=f,a[i^1].cap+=f;
if(!rest) break;
}
return flow-rest;
}
inline int Dinic(){
int flow=0;
while(bfs()) Copy(cur,head),flow+=dfs(S,INF);
return flow;
}
inline void Return(){for(int i=0;i<cnt;++i) a[i].cap=a[i].flow;for(int i=1;i<=n;++i) bel[i]=0;}
void Dfs(int u){bel[u]=1;for(int v,i=head[u];~i;i=a[i].next){v=a[i].to;if(a[i].cap&&!bel[v]) Dfs(v);}}
namespace GHT{
struct edge{int to,next,w;}a[N<<1];
int head[N],cnt=0;
inline void add(int x,int y,int z){a[++cnt]=(edge){y,head[x],z};head[x]=cnt;}
int tmp[N];
void Build(int l,int r){
if(l>=r) return;
S=que[l],T=que[r];Return();int Flow=Dinic();Dfs(S);
int L=l-1,R=r+1;add(S,T,Flow),add(T,S,Flow);
for(int i=l;i<=r;++i) {int u=que[i];if(bel[u]) tmp[++L]=u;else tmp[--R]=u;}
for(int i=l;i<=r;++i) que[i]=tmp[i];
Build(l,L),Build(R,r);
return;
}
map<int,int>vis;
int ans=0;
inline void DFS(int u,int fa,int Mi){
if(Mi!=INF) {if(!vis.count(Mi)) vis[Mi]=1,++ans;}
for(int v,i=head[u];i;i=a[i].next){
v=a[i].to;if(v==fa) continue;
DFS(v,u,min(Mi,a[i].w));
}
}
inline void work(){
for(int i=1;i<=n;++i) que[i]=i;
Build(1,n);
for(int i=1;i<=n;++i) DFS(i,0,INF);
cout<<ans<<endl;
return;
}
}
int main()
{
Set(head,-1);
init(n),init(m);
int u,v,w;
for(int i=1;i<=m;++i) {
init(u),init(v),init(w);
add(u,v,w),add(v,u,w);
}
GHT::work();
return 0;
}

【LuoguP3329&4123】[ZJOI2011]最小割&[CQOI2016]不同的最小割的更多相关文章

  1. [ZJOI2011]最小割 & [CQOI2016]不同的最小割 分治求最小割

    题面: [ZJOI2011]最小割 [CQOI2016]不同的最小割 题解: 其实这两道是同一道题.... 最小割是用的dinic,不同的最小割是用的isap 其实都是分治求最小割 简单讲讲思路吧 就 ...

  2. 【BZOJ2229】[ZJOI2011]最小割(网络流,最小割树)

    [BZOJ2229][ZJOI2011]最小割(网络流,最小割树) 题面 BZOJ 洛谷 题解 戳这里 那么实现过程就是任选两点跑最小割更新答案,然后把点集划分为和\(S\)联通以及与\(T\)联通. ...

  3. bzoj千题计划140:bzoj4519: [Cqoi2016]不同的最小割

    http://www.lydsy.com/JudgeOnline/problem.php?id=4519 最小割树 #include<queue> #include<cstdio&g ...

  4. 4519: [Cqoi2016]不同的最小割

    4519: [Cqoi2016]不同的最小割 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 489 Solved: 301 [Submit][Stat ...

  5. 【BZOJ4519】[Cqoi2016]不同的最小割 最小割树

    [BZOJ4519][Cqoi2016]不同的最小割 Description 学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分 ...

  6. bzoj4519: [Cqoi2016]不同的最小割(分治最小割)

    4519: [Cqoi2016]不同的最小割 题目:传送门 题解: 同BZOJ 2229 基本一样的题目啊,就最后用set记录一下就ok 代码: #include<cstdio> #inc ...

  7. BZOJ4519: [Cqoi2016]不同的最小割

    Description 学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成 两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割.对于带权图来说,将 ...

  8. 不同的最小割(cqoi2016,bzoj4519)(最小割树)

    学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成 两个部分,如果结点\(s,t\)不在同一个部分中,则称这个划分是关于\(s,t\)的割.对于带权图来说,将 所有顶 ...

  9. 【BZOJ-4519】不同的最小割 最小割树(分治+最小割)

    4519: [Cqoi2016]不同的最小割 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 393  Solved: 239[Submit][Stat ...

随机推荐

  1. python - 标准库:traceback模块

    traceback 模块: 允许你在程序里打印异常的跟踪返回 (Traceback)信息, 类似未捕获异常时解释器所做的. import traceback try: raise SyntaxErro ...

  2. 各种tips汇总

    才疏学浅,以下整理的东西有些可能还不成熟,措辞有待改进,但是都是我在敲代码的过程中,一点一滴积累总结的,如有不妥和错误,希望大家指正. 让行及元素变成块级元素的方式: position:absolut ...

  3. 阶段3 1.Mybatis_12.Mybatis注解开发_3 mybatis注解开发保存和更新功能

    使用直接来实现CRUD操作 Insert方法 创建测试类 把变量都定义在外面 写测试方法 修改链接的数据库 update方法 再加上address 被更新的数据

  4. 阶段3 1.Mybatis_05.使用Mybatis完成CRUD_9 Mybatis中的返回值深入-解决实体类属性和数据库列名不对应的两种方式

    sql语句里面起别名的方式 测试查询的方法 数据字段 都有值了. 配置查询接口列表和实体类属性名对应关系 id可以随便起名 主键的对应 再次测试,并没有封装成功 这是应为定义的对应关系并没有使用. 当 ...

  5. IntToHex

    IntToHex是一种函数,功能是将一个值转换成16进制形式的字符串. IntToHex(int Value, int Digits) 来源: 在Delphi.Pascal或C++ Builder中使 ...

  6. 学用 TStringGrid [6] - Options

    本例运行效果图: 一般修改 TStringGrid 的 Options 直接在设计时选一下 True 或 False 就行了; 代码中可以像下面操作:   StringGrid1.Options := ...

  7. 那些堪称神器的 Chrome 插件

    Chrome 的简洁快速以及丰富的插件种类使得它在国内日益盛行,帮助了我们很多 Chrome 用户提升了工作效率,而今天要给大家推荐8款实用甚至堪称神器的 Chrome 插件,希望对提升大家的工作效率 ...

  8. css随笔记(持续更新)

    /*DIV鼠标穿透*/ div{pointer-events:none;} /*清除IE11默认×*/ input::-ms-clear{display:none;} 使用伪类写边框部分三角 右上角三 ...

  9. 【MM系列】SAP MM模块-MIGO收货后自动打印收货单

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]SAP MM模块-MIGO收货后自动 ...

  10. python中的序列化和反序列化

    ~~~~~~滴滴,,什么是序列呢?可以理解为序列就是字符串.序列化的应用 写文件(数据传输) 网络传输 序列化和反序列化的概念   序列化模块:将原本的字典.列表等内容转换成一个字符串的过程就叫做序列 ...