网络流题目乱做

最大流

  • 直接网络流可以确定物品的分配的方案:"[POI2010] MOS-Bridges"
  • 环的限制可以转化为二分图匹配:"Luogu6061 [加油武汉]疫情调查"
  • 每条流量可以表示为一种不交的方案:"Luogu3358 最长 k 可重区间集问题"
  • 扩域可以很好地解决冲突:"Luogu3358 最长 k 可重区间集问题"

最大权闭合子图

  • 注意观察,矩阵可以转化为图论的选 or 不选的问题:"[TJOI2015] 线性代数"
  • 最大权闭合子图中,贡献为负数,就默认不计算,选择就会扣除贡献,如果为正数,就默认计算,不选就会扣除贡献:"[NOI2009] 植物大战僵尸"

  

最小割

普通最小割

  • 可以尝试建出最小割图,然后可以考虑分析最小割数量关系:"CF103E Buying Sets"
  • 最小割数量比较小的时候,就是两个点之间的关系比如联通/点双联通/点三联通了:"[CERC2015] Juice Junctions"

最小割树

上下界网络流

  

对偶图最短路

  

Hall 定理

  • 线段树维护 Hall 定理的式子:"[POI2009] LYZ-Ice Skates"
  • 集合具有完备匹配这一性质支持加法:"[CERC2016] 二分毯 Bipartite Blanket"

  

网络流 + 数据结构

  • CDQ 同时对于跨过中点的点对连边:"[SNOI2019] 通信"

  


  1. [POI2010] MOS-Bridges

    n(n1000) 个点和 m(m20000) 条边,每条边有两个权值,分别表示从 uv 和从 vu 的边权。

    求图中的一个欧拉回路,使得回路中的最大边权最小,并输出方案。


    考虑二分答案,转化为判定性问题。

    我们先连最小代价方向的边 (x,y),如果另外方向的边可以用,那么就可以让 degxdegx2,degydegy+2,因此我们可以把度数按照大小分类,接着跑网络流即可。(前提是所有节点 degxmod2=0

    有几个细节:

    • 最后输出方案的时候不能混合型的欧拉回路,应该根据网络流流量情况建边跑有向图欧拉回路。
    • 二分之前一定要判断这个图是否是弱联通的
    ↩︎
  2. Luogu6061 [加油武汉]疫情调查

    给一个有向图,求用若干个环(或点)将整张图覆盖的最小花费,环的代价就是环长,点的代价就是点的权值。

    n500,m5000


    想到基环树,我们会想到什么呢?就是环!如果基环树上的每个点的出边只有一条,且互不相同,那么就是若干个环以及自环了,这个就是匹配!

    考虑一张二分图,每个左部点和右部点的边权为其距离(如果编号相同,则为点权),那么题目的限制就是求一个完美匹配

    为什么呢?因为把匹配边连起来,一定形成环和若干个单点。

    于是比较暴力的想法:直接建图,然后 KM 或者费用流,复杂度 O(n4) ,因为新的 m 已经到了 n2 级别。

    大概率会被卡,考虑更加简单的做法:

    拆点,连边 (S,x,1,0),(x,x,1,ai),(x,T,1,0),(u,v,,w),(x,x,,0),最后一条边就方便了环的限制的刻画。

    跑费用流即可,复杂度 O(n2m)↩︎

  3. Luogu3358 最长 k 可重区间集问题

    给定实直线 Ln 个开区间组成的集合 I,和一个正整数 k,试设计一个算法,从开区间集合 I 中选取出开区间集合 SI,使得在实直线 L 上的任意一点 xS 中包含 x 的开区间个数不超过 k,且 zS|z| 达到最大(|z| 表示开区间 z 的长度)。

    这样的集合 S 称为开区间集合 I 的最长 k 可重区间集。zS|z| 称为最长 k 可重区间集的长度。

    对于给定的开区间集合 I 和正整数 k,计算开区间集合 I 的最长 k 可重区间集的长度。

    n300k3


    我们可以按照将方案划分为 k 个两两不相交的区间组,因此,可以考虑如下建图:

    • (S,1,k,0)
    • (i,i+1,k,0)
    • (ai,bi,1,biai)

    然后离散化后最大费用最大流就行了。 ↩︎ ↩︎

  4. [TJOI2015] 线性代数

    为了提高智商,ZJY 开始学习线性代数。

    她的小伙伴菠萝给她出了这样一个问题:给定一个 n×n 的矩阵 B 和一个 1×n 的矩阵 C。求出一个 1×n 的 01 矩阵 A,使得 D=(A×BC)×AT 最大,其中 ATA 的转置,输出 D

    1n500


    注意到 A 是一个 01 矩阵,那么可以代表选或者不选,因此 B 的意义就是 i,j 同时选的收益, C 的意义就是 i 的代价,接着就是最大权闭合子图了。 ↩︎

  5. [NOI2009] 植物大战僵尸

    给出一个 n×m 的网格图,每个点有一个植物,每个植物有其价值 P(可能为负数),然后有其保护位置(植物不死,僵尸就不能到那里),现在僵尸只能从某一行最后一列开始进攻并且吃掉植物,最大化僵尸最后的收益。

    n20,m30


    最大权闭合子图板子。

    考虑先 拓扑排序,删掉那些永远不可能吃的位置,如果最后某个植物和 S 联通,那么就是会被吃,否则与 T 联通,就不被吃。

    • P0 : ansans+P, (S,x,0),(x,T,P)
    • P<0 : (S,x,P),(x,T,0)
    ↩︎
  6. CF103E Buying Sets

    有一个大小为 n300 的全集,每个元素是一个数,有 n 个子集。题目保证任意 k 个子集的并的大小 k

    每个子集有一个可正可负的权值,你需要选出一些子集使得这些子集并的大小等于子集个数,且所选子集的权值和最小。可以为空集。


    神仙转换.jpg

    有一个比较奇怪的事情,n 个子集。

    我们考虑源点向每个集合连边,边权为 w,如果割掉就代表不选,每个集合向数连边 ,数向汇点连边 。跑最大流,假设边权全是正的,因为有完备匹配,那么割边条数一定 n,又边权到了 ,那么割边数目 n,因此割边数目 =n

    因此不选的集合 + 选的数字 = n,也就是 并集大小 = 集合个数。最后贡献取反即可。 ↩︎

  7. [CERC2015] Juice Junctions

    给出一张 n3000 个点,m4500 条边的无向图,每条边边权为 1,每个点度数不超过 3,求 a<bmincut(a,b)


    度数不超过 3,也就说明最小割不超过 3。

    分集中情况进行讨论:

    • 如果两个点不连通,那么答案为 0
    • 如果两个点联通,但是进行并不属于同一个点双联通分量,那么为 1
    • 如果两个点是属于同一个点三联通分量,那么为 3,否则为 2

    现在的问题就是如何判断两个点是否属于同一个点三联通分量了。

    注意到 m4500,于是可以考虑暴力删掉一条边,然后去判断每个点的点三联通分量情况,共 m 轮,每个点可以存一个 Hash 值,时间复杂度 O(n2+m2)↩︎

  8. 最小割树

    构建方法

    每次 rand 两个点 x,y ,然后求出这两个点之间的最小割,在最小割树上连边 (x,y),边权为最小割,然后会将整个集合分为两个小集合,递归下去不断构建即可。

    构建复杂度为 O(n3m)

    性质

    a,b 的最小割等于 (a,b) 在最小割树上边的最小值。

    下文定义 λ(a,b)a,b 的最小割。

    性质 1

    对于边 (x,y)p,q 分别属于该边两侧的子树,则有 λ(x,y)λ(p,q)

    如果不成立,那么割 (x,y) 的代价割不掉 (p,q)p,x 联通, q,y 联通,于是 (x,y) 没有割掉。

    性质 2

    对于任意不同的 a,b,cλ(a,b)min{λ(b,c),λ(a,c)}

    假设最小的是 λ(a,b),假设 c 在割掉 (a,b) 之后和 b 联通,那么由性质 1,λ(a,b)λ(a,c),有因为假设 λ(a,b) 最小,于是 λ(a,b)=λ(a,c)

    于是最小值至少有两个,下面就很好说明了。

    性质 2 推论

    对于 a,b, λ(a,b)min{λ(a,a1),λ(a1,a2),λ(at,b)}


    综合"性质 1" 和 "性质 2 推论",可得

    a,b 的最小割等于 (a,b) 在最小割树上边的最小值。

    int get(int x, int y) { 
        F :: reset(); F :: setst(x, y); 
        rep(i, 1, m) F :: link(u[i], v[i], w[i]), F :: link(v[i], u[i], w[i]); 
        return F :: runit(); 
    }
    
    void build(int l, int r) {
        if(l == r) return; int x = p[l], y = p[r], w = get(x, y);
        G[x].eb(y, w); G[y].eb(x, w);
        top = 0, top2 = l; rep(i, l, r) if(!F :: d[p[i]]) q[++top] = p[i]; else  p[top2++] = p[i];
        int cur = r; while(top) p[cur--] = q[top--];
        build(l, cur); build(cur + 1, r);
    }
    
    ↩︎
  9. CF343E Pumping Stations

    n100 个点,m1000 条边的带权无向图。

    你需要构造一个排列,收益为 i=2nmincut(ai1,ai)

    mincut(S,T) 表示图中 S 为源点,T 为汇点的最小割。

    求最大的收益,并输出方案。


    首先建立最小割树,然后定义两点之间距离为其在最小割树上边权的 min 值,问题就是:求一个排列,使得其路径之和最长。

    因为是 min 值作为路径,因此,答案的上界就是所有边权之和,我们可以考虑构造一种方案使得答案到达上界:

    • 树分治,然后每次在这个树中找到边权最小的边,对于 (x,y) 在树上的路径,如果跨过该边,那么距离就是该边权值了。
    • 因为该权值最小,我们要先尽量不经过这条边,分别把分出的两个集合走完,最后在跨过这条边,刚好经过一次。
    • 因此最后的答案是可以达到所有边权之和这一上界的。
    ↩︎
  10. [POI2009] LYZ-Ice Skates

    滑冰俱乐部初始有 1n 号码溜冰鞋各 k 双,已知 x 号脚的人可以穿 xx+d 号码的鞋子。现在有 m 次操作,每次两个数 r,x,表示 r 号脚的人来了 x 个,x 为负表示离开。对于每次操作,输出溜冰鞋是否足够。

    rnd,n,k,m5105,k109


    由 Hall 定理,记前缀和为 si,那么我们就是要:

    minlr{k(r+dl)(srsl)}0

    这个非常好办,拆项然后线段树维护。 ↩︎

  11. [CERC2016]二分毯 Bipartite Blanket

    在二分图中,所有点被划分成了两个不相交的集合 AB,每条边都恰好连接着某个 A 和某个 B。一个匹配是一个边集,满足没有任何两条边有相同的端点。我们称一个匹配 M 覆盖了点集 V 当且仅当 V 中的每个点都是 M 中至少一条边的端点。

    给定一个二分图,每个点有一个正整数权值。定义一个点集的权值为其中所有点的权值之和。

    给定一个参数 t,请统计有多少点集 V,满足 V 的权值不小于 t,且 V 被至少一个匹配 M 覆盖。

    1n,m201vi,wi1071t4×108

    首先有一个结论:

    • 在二分图中,如果 AB=,且各自有匹配覆盖 A,B,那么 AB 也是有匹配覆盖的。

    考虑将覆盖 A,B 的匹配拿出来,摆到一起:

    down1.png

    于是会形成若干个环和链,分类讨论环和链的情况就行了,长这样:

    down2.png

    剩下的就是对于左边集合和右边集合分别状压 DP check 一下,然后双指针即可。 ↩︎

  12. [SNOI2019] 通信

    n 个排成一列的哨站要进行通信。第 i 个哨站的频段为 ai

    每个哨站 i 需要选择以下二者之一:

    1. 直接连接到控制中心,代价为 W
    2. 连接到前面的某个哨站 j (j<i),代价为 |aiaj|。每个哨站只能被后面的至多一个哨站连接。

    请你求出最小可能的代价和。

    1n10000W,ai109


    考虑暴力网络流,我们把 x 拆为两个点 x,x,如果 x 流向 T 则代表和控制中心连接,如果 x 连向 y 那么就代表是连接 y,然后 y 在连向 T,代表把最多向后连的限制让给 x

    于是这么建图:

    • (S,x,1,0)
    • (x,T,1,W)
    • (x,y,1,|axay|) (x>y)
    • (x,T,1,0)

    暴力建边很可能 T 掉,于是考虑优化。

    我们可以用 CDQ + 归并处理。 ↩︎

  13. 性质 1

    对于边 (x,y)p,q 分别属于该边两侧的子树,则有 λ(x,y)λ(p,q)

    如果不成立,那么割 (x,y) 的代价割不掉 (p,q)p,x 联通, q,y 联通,于是 (x,y) 没有割掉。 ↩︎ ↩︎

  14. 性质 2 推论

    对于 a,b, λ(a,b)min{λ(a,a1),λ(a1,a2),λ(at,b)}


    综合"性质 1" 和 "性质 2 推论",可得

    a,b 的最小割等于 (a,b) 在最小割树上边的最小值。

    int get(int x, int y) { 
        F :: reset(); F :: setst(x, y); 
        rep(i, 1, m) F :: link(u[i], v[i], w[i]), F :: link(v[i], u[i], w[i]); 
        return F :: runit(); 
    }
    
    void build(int l, int r) {
        if(l == r) return; int x = p[l], y = p[r], w = get(x, y);
        G[x].eb(y, w); G[y].eb(x, w);
        top = 0, top2 = l; rep(i, l, r) if(!F :: d[p[i]]) q[++top] = p[i]; else  p[top2++] = p[i];
        int cur = r; while(top) p[cur--] = q[top--];
        build(l, cur); build(cur + 1, r);
    }
    
    ↩︎ ↩︎
posted @   Werner_Yin  阅读(89)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示