当前位置: 首页 > news >正文

最大网络流算法之dinic算法详解

1、题目描述

On the Internet, machines (nodes) are richly interconnected, and many paths may exist between a given pair of nodes. The total message-carrying capacity (bandwidth) between two given nodes is the maximal amount of data per unit time that can be transmitted from one node to the other. Using a technique called packet switching; this data can be transmitted along several paths at the same time.

For example, the figure shows a network with four nodes (shown as circles), with a total of five connections among them. Every connection is labeled with a bandwidth that represents its data-carrying capacity per unit time.

In our example, the bandwidth between node 1 and node 4 is 25, which might be thought of as the sum of the bandwidths 10 along the path 1-2-4, 10 along the path 1-3-4, and 5 along the path 1-2-3-4. No other combination of paths between nodes 1 and 4 provides a larger bandwidth.

You must write a program that computes the bandwidth between two given nodes in a network, given the individual bandwidths of all the connections in the network. In this problem, assume that the bandwidth of a connection is always the same in both directions (which is not necessarily true in the real world).

在这里插入图片描述
Input
Input starts with an integer T (≤ 30), denoting the number of test cases.

Every description starts with a line containing an integer n (2 ≤ n ≤ 100), which is the number of nodes in the network. The nodes are numbered from 1 to n. The next line contains three numbers s, t, and c. The numbers s and t are the source and destination nodes, and the number c (c ≤ 5000, s ≠ t) is the total number of connections in the network. Following this are c lines describing the connections. Each of these lines contains three integers: the first two are the numbers of the connected nodes, and the third number is the bandwidth of the connection. The bandwidth is a non-negative number not greater than 1000.

There might be more than one connection between a pair of nodes, but a node cannot be connected to itself. All connections are bi-directional, i.e. data can be transmitted in both directions along a connection, but the sum of the amount of data transmitted in both directions must be less than the bandwidth.

Output
For each case of input, print the case number and the total bandwidth between the source node s and the destination node t.

Sample
在这里插入图片描述
原题链接:Internet Bandwidth

2、思路分析

最大网络流问题,一定要指明每条线路的承载量,一定要指明源点和目标点。
在这里插入图片描述
该有向图中,从A到D的整个流最大是130。

dinic算法的核心在于负反馈,补反向边的代价,解决的是成环节点的问题。

举个例子:
在这里插入图片描述
两种走法:

  • A->B->D,最小边50,所以每条边减50,然后增加反向的50的边
  • A->C->D,最小边30,所以每条边减30,然后增加反向的30的边

即:
在这里插入图片描述
Dinic算法还有两个优化的点。

第一个优化的点——建立高度数组:先广度优先遍历,确定每个节点所在的层数,然后使用深度优先遍历,如果某个节点有多条路可以选择,选择节点所在层数比当前节点层数大的路径。

例如:
在这里插入图片描述
从 A 出发,进行广度优先遍历,则:
在这里插入图片描述
建立一个高度数组,记录每个点所在的层数:

层数数组:[0, 1, 1, 2]
节点: 	 A 	B  C  D

然后从A出发往前走到时候,只选择层数变大的路:A->B,因为A是0层,B是1层;B不能到C,因为二者层数相同,按照这种规则,所以路线就是A->B->D 和 A->C->D。

总结来说,就是先建立起高度数组,然后DFS,这样可以避免来回走的问题。

第二个优化的点——建立一个数组,记录每个节点经过的支路。
在这里插入图片描述
A->B,传输100,B->E,传输100,此时到E这里要往D传输100,E先选择10这条路,该路径使用了就变成0,还剩100-10 = 90要传输,接着选择20,该路径也变成0;还剩90-20=70要传输,接着选择30,该路径也变成0;还剩70-30=40要传输,接着选择50这条路,只需要占用40,该路径变成10。此时100的任务传输完成。
在这里插入图片描述
若此时A->C,传输60,C->E传输60,此时E要往D传输60,而可用的路径只有10和150这两条,其他路径不再考虑。

3、代码实现

// 本题测试链接:
// https://lightoj.com/problem/internet-bandwidth
// 这是一道DinicAlgorithm算法的题
// 把如下代码粘贴进网页所提供的java编译器环境中
// 不需要修改任何内容可以直接通过
// 请看网页上的题目描述并结合main函数的写法去了解这个模板的用法
// 请务必参考如下代码中关于输入、输出的处理
// 这是输入输出处理效率很高的写法
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;public class DinicAlgorithm {public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));StreamTokenizer in = new StreamTokenizer(br);PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));while (in.nextToken() != StreamTokenizer.TT_EOF) {int cases = (int) in.nval;for (int i = 1; i <= cases; i++) {in.nextToken();int n = (int) in.nval;in.nextToken();int s = (int) in.nval;in.nextToken();int t = (int) in.nval;in.nextToken();int m = (int) in.nval;Dinic dinic = new Dinic(n);for (int j = 0; j < m; j++) {in.nextToken();int from = (int) in.nval;in.nextToken();int to = (int) in.nval;in.nextToken();int weight = (int) in.nval;//因为是无向图,所以要加4条边,而addEdge一次加两条,所以调用两次addEdgedinic.addEdge(from, to, weight);dinic.addEdge(to, from, weight);}int ans = dinic.maxFlow(s, t);out.println("Case " + i + ": " + ans);out.flush();}}}public static class Edge { //有向边public int from; //点的编号,边的起点public int to; //点的编号,边的终点public int available; //边的剩余可用承载量public Edge(int a, int b, int c) {from = a;to = b;available = c;}}public static class Dinic {//点的数量private int N; //edges记录所有的边,包括反向边//假设有第0条边 (1,3,20), 第1条边(3,2,10)//根据第0条边生成 (1,3,20) 和 (3,1,0) , 根据第1条边生成 (3,2,10) 和 (2,3,0),反向边的available记录的就是使用的量//将生成的边记录到edges中:[(1,3,20), (3,1,0), (3,2,10), (2,3,0)]private ArrayList<Edge> edges; //nexts记录每个点和哪些边有关://0 : {}  表示和点0相关的边没有//1 : {0}  表示和点1相关的点是edges数组中的第0条边,记录的是边的编号//2 : {3}  表示和点2相关的点是edges数组中的第3条边,记录的是边的编号//3 : {1,2} 表示和点3相关的点是edges数组中的第1和第2条边,记录的是边的编号//因为边和反向边是成对出现的,假设某条边编号是i,异或1,即 (i^1) 就能得到它的反向边编号 private ArrayList<ArrayList<Integer>> nexts;//高度数组private int[] depth;//记录当前点用到了哪些边,接下来要走的边从哪条开始//比如一开始点1有四条边与其相关 {0, 1, 2, 3}//从第0条边开始使用,则cur[1] = 0//若经过某次操作后,还剩下2和3这两个编号的边可用,则此时cur[1] = 2private int[] cur; public Dinic(int nums) {N = nums + 1; //在N个点的基础上补一个,则点的编号无论从0还是从1开始都可以nexts = new ArrayList<>();for (int i = 0; i <= N; i++) { //每个点都有边列表,所以一共N个nexts.add(new ArrayList<>());}edges = new ArrayList<>();depth = new int[N];cur = new int[N];}//添加边:从u到v的边,可用承载量是r,成对增加的//对于无向图来说,如A-B,边的权值为20,则一共要产生四条边:(A,B,20) (B,A,0), (B,A,20),(A,B,0)public void addEdge(int u, int v, int r) {int m = edges.size(); //先获取edges数组的长度,此时已经存在的边下标就是0~m-1edges.add(new Edge(u, v, r)); //将新的边添加到edges数组中nexts.get(u).add(m); //u这个点与其相关的边要增加上新添加的边,而新添加的边的在edges数组中的下标就是m edges.add(new Edge(v, u, 0)); //添加反向边nexts.get(v).add(m + 1);}//最大网络流算法public int maxFlow(int s, int t) {int flow = 0;while (bfs(s, t)) { //一直循环,直到没有s到t的路径Arrays.fill(cur, 0); //表示当前这个点s是从next中与它相关的的哪条边开始的,边权值为0时是不可走的,直接跳过,一开始默认每个点都是从第0号边开始的flow += dfs(s, t, Integer.MAX_VALUE); //要传输的流量默认为很大Arrays.fill(depth, 0);}return flow;}//广度优先搜索//功能:(1)标记t是否能到;(2)记录高度,标记高度数组private boolean bfs(int s, int t) {//隐含了每一个s所在的层数都是第0层//因为之前初始化depth时,所有的值都是默认为0//广度优先搜索用队列LinkedList<Integer> queue = new LinkedList<>();queue.addFirst(s);//布尔类型是为了进过队列的点不再进入boolean[] visited = new boolean[N];//源点,第一个被访问visited[s] = true;while (!queue.isEmpty()) {int u = queue.pollLast();for (int i = 0; i < nexts.get(u).size(); i++) { //遍历next数组中与当前点u相关的边的编号Edge e = edges.get(nexts.get(u).get(i)); //取出边的编号对应的边int v = e.to;if (!visited[v] && e.available > 0) { //只关心路径权值>0的点visited[v] = true;depth[v] = depth[u] + 1;if (v == t) {break;}queue.addFirst(v);}}}return visited[t];}// 当前来到了s点,s可变// 最终目标是t,t固定参数// r,收到的任务// 收集到的流,作为结果返回,ans <= rprivate int dfs(int s, int t, int r) {if (s == t || r == 0) {return r;}int f = 0;int flow = 0;// s点从哪条边开始试 -> cur[s]for (; cur[s] < nexts.get(s).size(); cur[s]++) {int ei = nexts.get(s).get(cur[s]);//边和反向边都获得Edge e = edges.get(ei);Edge o = edges.get(ei ^ 1);//下一个点高度(层数)比当前点大,才往下走//且 下一个点能到t且它完成的任务流量 f 不等于0   Math.min(e.available, r)在任务和边的权值中选择较小的if (depth[e.to] == depth[s] + 1 && (f = dfs(e.to, t, Math.min(e.available, r))) != 0) {e.available -= f; //边的承载量 - fo.available += f; //反向边 + fflow += f; //完成的流 + fr -= f; //上一个节点派下来的任务 - f if (r <= 0) { //任务完成break;}}}return flow;}}}

相关文章:

最大网络流算法之dinic算法详解

1、题目描述 On the Internet, machines (nodes) are richly interconnected, and many paths may exist between a given pair of nodes. The total message-carrying capacity (bandwidth) between two given nodes is the maximal amount of data per unit time that can b…...

051、面试必刷TOP101--链表(230503)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言链表1、BM1 反转链表2、BM2 链表内指定区间反转3、BM3 链表中的节点每k个一组翻转4、BM4 合并两个排序的链表5、BM5 合并k个已排序的链表6、BM6 判断链表中是否…...

开源中国面试准备

dockerFile常见命令 1、FROM 设置要制作的镜像基于哪个镜像&#xff0c;FROM指令必须是整个Dockerfile的第一个指令&#xff0c;如果指定的镜像不存在默认会自动从Docker Hub上下载 2、MAINTAINER 镜像作者的信息&#xff0c;比如名字或邮箱地址 语法&#xff1a;MAINTAINER n…...

基于J2EE的B2C电子商务系统开发与实现

摘要 当今社会,科学技术突飞猛进,知识经济初见端倪。电子商务作为一种新型的贸易方式,极大地促进了全球经济贸易的发展,同时也正在改变人们的生活方式和思想观念。电子商务是指整个贸易活动实现电子化,交易各方以电子交易方式而进行的商业交易。世界贸易组织电子商务专题报告定…...

三分钟教你看懂 spring 官方文档

新手如何学会查看官方文档API 首先进入官网&#xff1a;这里以 spring boot 为例 &#xff0c;进入spring 官方地址 我们进入 spring boot 这里我们要看文档当然是要 learn 了&#xff0c;所以点进去。 我需要的东西在 IO 模块里面&#xff0c;点 IO 进入 发送邮件是不是有了…...

基于simulink使用射频模块集天线块对天线阵列的射频系统进行建模

一、前言 本 例 说明 如何 对 包括 天线 阵列 的 MIMO 接收 和 发射 RF 系统 进行 建模。该设计从单个RF链的预算分析开始&#xff0c;然后扩展到多个天线。RF Blockset 天线模块对天线阵列进行全波分析&#xff0c;支持对效应和缺陷进行高保真建模&#xff0c;并结合射频系统的…...

从小学习编程的路线与编程进阶

对于从小学习编程的学生&#xff0c;通常会从基础的编程概念和语法开始学习。以下是一个可能的路线&#xff1a; 1. 学习计算机基础知识&#xff0c;包括计算机硬件、操作系统和网络等基本概念。 2. 掌握基本的编程概念和语法&#xff0c;例如变量、数据类型、条件语句和循环语…...

[实训] 实验1-SPI数据传输基础实验(上)

目 录​​​​​​​ 一、实验目的 二、实验仪器及器件 三、实验内容及原理 四、实验步骤​​​​​​​ 五、实验测试数据表格记录 六、实验数据分析及处理 七、实验结论与感悟 一、实验目的 使用FPGA/ARM实现SPI数据传输实验&#xff1b;实现数据传输程序的编写、下载…...

微软骚操作恶心Win10用户,上网得先看广告

IE 浏览器在几个月前被彻底禁用&#xff0c;预装了快30年的老古董也确实到了退役的时候。 而微软也早有准备&#xff0c;2015年随着 Win10 发布推出了 Microsoft Edge 浏览器。 2020年迁移到 Chromium 内核让其成为了主流浏览器之一。 和 Chromium 系其他浏览器一样支持扩展插…...

为了做低代码平台,这些年我们对.NET的DataGridView做的那些扩展

我们的低代码开发平台从一开始决定做的时候&#xff0c;就追求未来能够支持多种类型的客户端&#xff0c;目前支持Winform&#xff0c;Web&#xff0c;H5&#xff0c;FlutterAPP&#xff0c;当然了&#xff0c;未来也有可能会随着实际的需要淘汰掉一些客户端的。 为了系统更易…...

洛谷 子集积 题解

题目 P1 背包 子集积 > m >m >m 个数并不好求&#xff0c;考虑子集积 ≤ m \le m ≤m 的个数 x x x&#xff0c;答案即为 ( 2 n − x ) (2^n - x) (2n−x)。 对于子集积 ≤ m \le m ≤m 的个数&#xff0c;可以化为 0-1 背包问题做&#xff0c; f i , j f_{i,…...

Boost笔记 1:下载、编译、安装、测试

1. 下载 当前版本是1.82&#xff0c;下载链接&#xff1a; https://boostorg.jfrog.io/artifactory/main/release/1.82.0/source/ 2. 安装编译依赖库 本地环境是Ubuntu 22.04&#xff0c;需要安装以下依赖库&#xff0c;部分影响boost相关功能的开启&#xff0c;部分影响编译…...

tiechui_lesson01_入口函数和卸载函数

主要讲解入口函数和卸载函数。 #include <ntifs.h>VOID nothing(HANDLE ppid, HANDLE mypid, BOOLEAN bcreate) {UNREFERENCED_PARAMETER(ppid);UNREFERENCED_PARAMETER(mypid);UNREFERENCED_PARAMETER(bcreate);DbgPrint("processNotify\n"); }VOID DriverU…...

密码学【java】初探究加密方式之非对称加密

文章目录 非对称加密1 常见算法2 生成公钥和私钥3 私钥加密4 私钥加密 公钥解密5 公钥和私钥的保存和读取5.1 **保存公钥和私钥**5.2 读取公钥和私钥 非对称加密 非对称加密算法又称现代加密算法。非对称加密是计算机通信安全的基石&#xff0c;保证了加密数据不会被破解。与对…...

网络安全和黑客技能:15本必读书籍推荐

前言 网络安全和黑客技能紧密相连。想要有效地防范黑客攻击&#xff0c;了解黑客的技能和思维方式非常重要。而要想成为一名合格的白帽黑客&#xff0c;也需要深入理解网络安全的基本原理和最佳实践。本文将介绍15本网络安全和黑客书籍&#xff0c;既包括了防范黑客攻击的指南…...

电话号码的字母组合

题目&#xff1a;17. 电话号码的字母组合 - 力扣&#xff08;Leetcode&#xff09; 思路&#xff1a; 给定一个电话号码字符串 digits&#xff0c;须输出它所能表示的所有字母组合。我们可以先定义一个数字字符到字母表的映射表 numToStr&#xff0c;然后再用 Combine 函数递归…...

PAT A1032 Sharing

1032 Sharing 分数 25 作者 CHEN, Yue 单位 浙江大学 To store English words, one method is to use linked lists and store a word letter by letter. To save some space, we may let the words share the same sublist if they share the same suffix. For example, l…...

Git常见问题汇总

问题&#xff1a;Your branch is ahead of ‘origin/master’ by 1 commit 原因&#xff1a;你的本地分支高于远程仓库一次提交, 同步更新下&#xff0c;执行命令&#xff1a; git push origin master问题&#xff1a;warning: LF will be replaced by CRLF in main.lua The …...

设计模式之代理模式(静态代理动态代理)

目录 1、什么是代理模式 2、代理模式的结构 3、代理模式的实现 3.1 静态代理和动态代理概念 3.2 静态代理 3.3 动态搭理 3.3.1 代码实现 3.3.2 Proxy类讲解 4、动态代理VS静态代理 5、代理模式优缺点 1、什么是代理模式 由于某些原因需要给某对象提供一个代理以控制对…...

Java并发编程基础知识概述

前言 在现代计算机系统和服务器中&#xff0c;多线程并行执行已经成为常态&#xff0c;而且并发编程能够充分利用系统资源&#xff0c;提高程序处理效率和质量。因此&#xff0c;Java并发编程是Java程序员必须掌握的重要技能之一。 线程和进程 在操作系统中&#xff0c;进程是…...

Redis超详细入门手册教程!还不快来看看?

地址&#xff1a; RedisRedis is an open source (BSD licensed), in-memory data structure store, used as a database, cache, and message broker. Redis provides data structures …https://redis.io/ 1&#xff1a;NoSQL简介 1.1&#xff1a;数据库应用的演变历程 单…...

代码随想录算法训练营第四十九天| 121. 买卖股票的最佳时机、122.买卖股票的最佳时机II

文章目录 121. 买卖股票的最佳时机122.买卖股票的最佳时机II 121. 买卖股票的最佳时机 为什么定义dp数组为二维数组&#xff1f; dp数组定义&#xff0c;dp(i)[0] 表示第i天持有股票所得最多现金&#xff0c;dp(i)[1]表示第i天不持有股票的状态&#xff08;未必当前卖出&#x…...

零基础如何学习挖漏洞?看这篇就够了【网络安全】

前言 有不少阅读过我文章的伙伴都知道&#xff0c;我从事网络安全行业已经好几年&#xff0c;积累了丰富的经验和技能。在这段时间里&#xff0c;我参与了多个实际项目的规划和实施&#xff0c;成功防范了各种网络攻击和漏洞利用&#xff0c;提高了安全防护水平。 也有很多小…...

Twitter 推荐算法底有多牛? 已斩获11.7K star

点击上方“Github中文社区”&#xff0c;关注 看Github&#xff0c;每天提升第070期分享 &#xff0c;作者&#xff1a;Huber | Github中文社区 大家好&#xff0c;我是Huber。 在美国当地时间 3 月 31 日&#xff0c;马斯克履行当初的诺言&#xff0c;他宣布了 Twitter 算法的…...

看过这篇文章,读懂数据分析

一、为什么需要数据分析 数据分析的重要性不言而喻&#xff0c;没有数据&#xff0c;就是感性。数据不会被观点打败&#xff0c;数据只能被数据打败。我们现在妥妥地已经进入了数据时代。 量化IT投资成效&#xff0c;以数据驱动决策 站在公司或者决策者角度&#xff0c;数据最…...

[计算机图形学]光场,颜色与感知(前瞻预习/复习回顾)

一、Light Field / Lumigraph—光场 1.我们看到的是什么 我们的眼睛能够把3D世界转换为2D的成像信号被我们感知&#xff0c;如上面第一幅图&#xff0c;这就是我们看到整个世界的过程&#xff0c;那么如果我们把之前记录的光的信息都完美的放在一个幕布上&#xff0c;那么我们…...

L4公司进军辅助驾驶,放话无图也能跑遍中国

作者 | Amy 编辑 | 德新 高阶智能驾驶走向规模量产&#xff0c;高精地图成为关键的门槛之一。今年&#xff0c;多家车企和智驾公司都喊出「不依赖高精地图&#xff0c;快速大规模落地」的口号。 华为、小鹏、元戎以及毫末等&#xff0c;可能是最快在国内量产 无高精图智…...

【Java笔试强训 17】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;杨辉三角…...

【IPv6】基本概念及字段

IPV4知识点&#xff1a; 字段值 IPv4字段共 字段值解释Version版本版本字段&#xff0c;可以区分V4和V6版本&#xff0c;V4是0100&#xff0c;V6是0110&#xff0c;需要注意的是V4和V6头部除了版本字段位置相同外&#xff0c;其他都是不一样的&#xff0c;因此两个协议不能直…...

数据库中的 Schema 变更实现

线上沙龙-技术流第 30 期营业啦 05月09日&#xff08;周二&#xff09;19:30 KaiwuDB - B站直播间 传统数据库操作 Schema 变更时&#xff0c;第一步便是锁表&#xff0c;需持续到 Schema 变更操作完成。这样的做法虽然实现简单&#xff0c;无需考虑事务并发带来的影响&#…...

浏阳做网站推荐/外链推广论坛

本站使用「署名 4.0 国际 (CC BY 4.0)」许可协议&#xff0c;欢迎转载、或重新修改使用&#xff0c;但需要注明来源。 署名 4.0 国际 (CC BY 4.0)本文作者: 苏洋创建时间: 2018年07月19日统计字数: 2595字阅读时间: 6分钟阅读原始链接: https://soulteary.com/2018/07/19/clean…...

效果图网站模板/app拉新推广平台

快哟&#xff0c;等下版主就给我移除了&#xff0c;就没有了啊...... 强烈推荐&#xff1a;《JavaScript设计模式》 理由&#xff1a;异常生猛的一本书&#xff0c;看书名带“设计模式”就知道&#xff0c;这本书想要读明白有点困难&#xff0c;本人自己感觉&#xff0c;只要某…...

网站空间最便宜/seo专业培训班

定义&#xff1a; 指多个对象间存在一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式&#xff0c;它是对象行为型模式。 优点&#xff1a; 1、降低了目标与观…...

网站建设滕州信息港/关键词优化的原则

参考:https://www.cnblogs.com/yuanchenqi/articles/5722574.html https://blog.csdn.net/zhuangzi123456/article/details/84400108 一.事件驱动模型(一种编程范式) 协程:遇到IO切换 但何时切回去?如何确定IO操作结束?—>通过回调函数 传统的编程是如下线性模式的: 开…...

网站免费推广方案/市场营销专业就业方向

我在听这张,真好听 很怀念那些听歌的日子...

做网站正规公司/全网媒体发布平台

nginx指定多个域名跨域请求配置什么是跨域假设我们页面或者应用已在 http://www.test1.com 上了&#xff0c;而我们打算从 http://www.test2.com 请求提取数据。一般情况下&#xff0c;如果我们直接使用 AJAX 来请求将会失败&#xff0c;浏览器也会返回“源不匹配”的错误&…...