网络流题目详讲+题单(提高版)(持续更新中......)

PS:如果你觉得自己还不够强(和我一样弱),可以去入门版看看

写在前面的话(潦草)

  • 这篇博客不会讲定义,理解啊什么的,那些知识点网络上......仅仅是题目详讲
    但是每一道题的题解和知识点还是会涵盖的
  • 笔者还很菜,还有很多不会,只是想让自己会了的题目大家更容易懂
  • 建议使用博客右边的主题切换,换成夜间模式可能看起来更舒服(随性)
  • 笔者根据自己的感受(也有一定参考性的)给题目编了个难度,有主观色彩,可以根据实际需要来选择

前置知识点:

网络流题目详讲(入门版)

题目来了:

PS:若无特殊说明,均为luogu上的题目,难度有标记

网络最大流/一般增广路(Dinic&EK)

  • [X] ☆☆☆最小路径覆盖问题(网络流24题)(其实有些地方把这个模型当板子了......)

    1. 首先需要看懂题目(没错,我看了很久),是让很多条不相交的路径去覆盖所给的图,问最少要多少条并输出它们。
    2. 然后需要证明一个东西:我们一开始把每个点看做一条路径,考虑路径合并的问题,每两条路径首尾相连接起来是不是路径数就会减一?(显然)。而我们会要尽量减少它们的数量。
    3. 想一下怎么可以求出点可以连起来的路径的数量最小值,根据上面2提到的那一点,我们就可以考虑把可以合并的点数全部求出来,再拿总点数去减,是不是就是我们要求的答案了?
      那么问题就转化为了求哪些点可以“合并”。然后再往后看,嗯,标签是网络流,就考虑建图跑吧。
    4. 有了上面的基础应该就不难想了,把每个点分开成两个,X[i]与源点S连容量为1的边,Y[i]与汇点T连容量为1的边(每个点只能在一条路径上),然后数据读入的边X[i] --1--> Y[j]这个毋庸置疑了吧。最后跑Dinic求最大流就行了就行了(我建议把样例的图根据我讲的画出来容易理解,其实不难)
    5. 最后考虑怎么输出路径,很容易想到,在Dinic的DFS过程中可以记录每个点流向的那个点(就是会在原图上相连的点,标记一下每一条“输出边”的开头位置,暴力跳着输出就ok)
      实在不行还是一边看代码
  • [X] ☆☆☆☆☆奶牛隐藏(最大流(费用流是错的))

    这道题要讲的话真的太累了,而且不想放图也很难讲懂,所以......(敬请谅解)
    但是相信我,同机房有个神犇Flash Hu巨佬在洛谷里发了一篇题解,讲的贼JB
    这里再提供他的博客地址(打个广告yeh):https://www.cnblogs.com/flashhu/

  • [ ] 最长不下降子序列问题(网络流24题)

费用流

  • [X] ☆☆☆☆☆洞穴遇险

    1. 难度很大,我一开始并不会做,听了zkj的讲解才会做的(我是真的弱)
    2. 首先必须要想尽一切办法把那个三角柱抽象成一条路径(从一个端点进经过转口(支撑部位)再从另一个端点出),抽象完之后会好理解很多......
    3. 一个不需要脑子的地方:我们的三角柱转角肯定放在i+j为奇数的地方
    4. 开始建图:(i+j为奇数简称奇数点,偶数点同理)
      首先,我很不幸地告诉你,这个题目要把点排成四列,而且......我理解了很久才懂
  • 首先奇数点和偶数点肯定是要分开的对吧(毋庸置疑),那么我将会把奇数点和偶数点分别排成两列(先别问为什么,网络流的建边从来没有为什么,都是套路,对了就行)
  • 然后奇数点肯定要拆点(因为会产生贡献,所以要对自己连边),我们把这两列放在四列点的中间两列(说了抽象成路径,奇数点是要在石头的转角处被经过的,路径中间)
  • 偶数点的话 (PS:不管我bb什么,这段话都是偶数点):
    你会发现一个性质:"石头"路径肯定是从一个奇数列(或者偶数列)上的偶数点连到欧数列上的另一个偶数点(奇数点),总之就是起点和终点的列数奇偶不同(yeh,简单明了),所以把奇数列的点放在左边(放右边是一样的),再把偶数列放在右边,我们就强制好了出口和入口(左右是对称的,没有区别)
  • 考虑连边:
    ①首先,上面已经说过了,中间的两列奇数点分别自己对自己连一条流量为1,费用为点权的边
    ②其次,对于所有的偶数点,从源点向第一列每个点连一条流量为1费用为0的边,从第四列向汇点连一条流量为1费用为0的边
    ③最后,相邻的点肯定要连边对吧,从第一列向这个点在图上相邻的点(一定在第二列中的)连容量为1,费用为0的边,第三列向第四列连边也同理
  1. 不用想了,套板子,跑一个最大费用最大流,最后拿所有点的点权之和减掉就是答案了(因为我们求得的是最大覆盖住多少)
  2. 你问我要代码?不行,得让你先经历痛苦,再去看洛谷的题解的代码吧
    (其实就是码的太丑了怕丢人)

预流推进算法(一种新的很吊的求最大流的方法,据说非常优秀)

网络流题目需要注意的地方

PS:代码尚未过编译,现场手打的,有错误请指出
PS:有些凌乱,凑合着看

Part1 一定要记得

1. 建边时的"反边容量0"和"反边费用负"

il void add(rg int p,rg int q,rg int o,rg int w)
{//o为容量,w为费用(变量丑)
    ljl[++cnt]=(EDGE){q,hd[p],o, w},hd[p]=cnt;
    ljl[++cnt]=(EDGE){p,hd[q],0,-w},hd[q]=cnt;
}

2. EK算法记录前驱并处理情况的跳点情况

    int flow=Inf;
    for(int i=T;i!=S;i=ljl[pre[i]^1].to)
        flow=min(flow,ljl[pre[i]].c);
    tot+=flow,ans+=flow*dis[T];
    for(int i=T;i!=S;i=ljl[pre[i]^1].to)
        ljl[pre[i]].c-=flow,ljl[pre[i]^1].c+=flow;

3. 当前弧优化记得每次都要重新赋值cur

while(BFS())
{
    for(int i=1;i<=n;++i)cur[i]=hd[i];//<--
    while(lst res=dfs(1,n,Inf))ans+=res;

4. 跑Dinic分层时dep[S]一定要赋值为1,不然死循环

    Q.push(S),dep[S]=1;//<--

5. 增广路时数组清零(还有数组的边界)

其实边界的话,我一般把S放在0号节点,T放在最后的节点,循环的时候就会顺手很多

    //Dinic的BFS
    for(int i=S;i<=T;++i)dep[i]=0;//<--

    //费用流的SPFA
    for(int i=S;i<=T;++i)dis[i]=Inf;//<--跑最大费用则为-Inf
    while(!Q.empty())Q.pop();
    dis[S]=0,Q.push(S),in[S]=1;

6. 费用流和最大流都可以跑环

Part2 技巧

看看xzy吧,很详细的

原文地址:https://www.cnblogs.com/cjoierljl/p/9489471.html

时间: 2024-10-10 00:48:25

网络流题目详讲+题单(提高版)(持续更新中......)的相关文章

算法之路——POJ刷题(Java,持续更新中)

先拿一些水题来练手了 1.POJ1000 import java.util.Scanner; /** * Created by mxcsky on 2015/1/25. */ public class POJ1000 { public static void main(String[] args){ Scanner in = new Scanner(System.in); int a = in.nextInt(); int b = in.nextInt(); System.out.println

Android 系统中,那些能大幅提高工作效率的 API 汇总(持续更新中...)

前言 "条条大路通罗马."工作中,实现某个需求的方式往往不是唯一的,这些不同实现方式不仅表现在代码质量上,还影响着我们的工作效率.就像,在 Android 系统中,总有那么一些鲜为人知的 API 能够减少我们很多零碎的工作量.于是,就想凭着一些经验,整理一些常用的,找个地方归纳总结,也供日后翻阅. getResources().getIdentifier(String name, String defType, String defPackage) 根据资源名称获取资源 id.正常情况

PTA|团体程序设计天梯赛-练习题目题解锦集(C/C++)(持续更新中……)

PTA|团体程序设计天梯赛-练习题目题解锦集(持续更新中) 实现语言:C/C++:      欢迎各位看官交流讨论.指导题解错误:或者分享更快的方法!! 题目链接:https://pintia.cn/problem-sets/994805046380707840/problems 目录 (点击对应题目即可进入相应题解--小声BB--) L1-001 Hello World (5 分) L1-002 打印沙漏 (20 分) L1-003 个位数统计 (15 分) L1-004 计算摄氏温度 (5

js坑爹笔试题目汇总(持续更新中)

把你的面试官问倒,你就是一个合格的面试者了,下面总结一些易错的js笔试题目,会持续更新中,欢迎关注 1,考察this var length = 10 function fn(){ alert(this.length) } var obj = { length: 5, method: function(fn) { fn() // ? arguments[0]() // ? } } obj.method(fn) 这里的坑主要是arguments,我们知道取对象属于除了点操作符还可以用中括号,这里fn

2020年面试算法题合集(北京中小公司版)持续更新

数组 链表 1. 剑指offer24:反转链表 (leetcode206. Reverse Linked List) 方法1: iterative 记忆点: 采用pre,cur,next3个指针进行迭代 关键点: 分析出有3个指针: pre,cur,next. for的终止条件cur != nil表示每个链表节点都需要翻转一次. 以链表[1,2,3]为例,cur != nil可以使得1,2,3都分别作为cur执行一次循环. 返回的指针是pre.因为退出循环的条件是cur==nil,退出循环后的指

素数相关?(有关素数的题持续更新中)x

素数(大体举几个栗子): 素数相关知识: 素数概念: 最大公约数只有1和它本身的数叫做质数(素数) 素数小性质: 1.大于一的整数必有素因数. 2.设p是素数,n是任意一个整数 能够推出p|n,(p,n)=1; 3.设p是素数,a,b为整数,若p|ab,则ab中至少有一个能被p整除 4.素数有无穷多个证明: (素数与整数之间的关系:1整除2互素) 假定正整数中只有有限个素数 设p1,p2……pk为从小到大排列起来的数 且N=p1*p2*……pk 设M=N+1 如果M为素数,那么M要大于p1,p2

算法和数据结构基础题集(持续更新中)

 注意一题多解,举一反三,从普通算法到最优算法 1.判断一个字符串中的字符是否唯一(即没有重复),不能使用额外的数据结构(使用基本的数据结构) 2.反转一个字符串 3.去掉字符串中的重复字符,不能使用额外的缓存空间 4.判断两个字符串是否是变位词(两个单词字符相同,但是位置不同的单词) 5.写一函数,把字符串的空格替换为%20 6.判断字符串是否是另一个字符串的字串 7.从一个未排序的链表去除重复的项,不允许使用临时的缓存 8.从一个单链表中返回倒数第k个元素 9.删除链表中的给定节点 10

LeetCode Animation 题目图解汇总(持续更新中...)

我会尽力将LeetCode上所有的题目都用动画的形式演示出来,期待与你见证这一天! GitHub Repo:LeetCode Animation Follow: MisterBooo · GitHub Problems ID Problem Article Animation 001 两数之和 每天一算:Two Sum 019 删除链表的倒数第N个节点 每天一算:Remove Nth Node From End of List 020 有效的括号 每天一算:Valid Parentheses 0

leetcode刷题全纪录(持续更新)

338. Counting Bits 原题链接https://leetcode.com/problems/counting-bits/ 自己的思路:Integer.bitCount()方法,但是原题并不推荐使用内嵌方法 bug free:遇到偶数时,其1的个数和该偶数除以2得到的数字的1的个数相同,遇到奇数时,其1的个数等于该奇数除以2得到的数字的1的个数再加1 public int[] countBits(int num) { int[] result = new int[num+1]; fo