1、代码实现

package Graph;import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;public class dinic {//定义一个哈希表,即字典,构造原始的图HashMap<String, HashMap<String,Integer>> original_graph;HashMap<String, HashMap<String,Integer>> residual_graph;//定义层次图,层次图的边只能从起点到1,1到2,2到3,以此类推HashMap<String, HashMap<String,Integer>> level_graph;ArrayList<Integer> residual_flow_value = new ArrayList<Integer>();ArrayList<String> residual_flow_path = new ArrayList<String>();int augmented_value, maximum_flow;boolean is_blocking_flow = false;//流量 flow 容量  Capacitypublic dinic() {// TODO Auto-generated constructor stuboriginal_graph = new HashMap<String, HashMap<String,Integer>>();residual_graph = new HashMap<String, HashMap<String,Integer>>();level_graph = new HashMap<String, HashMap<String,Integer>>();augmented_value = 0;}public void initial_original_graph() {//只能用来查询,不能修改
//      Integer[] weight_edge = new Integer[]{1,2};original_graph.put("s",new HashMap<String,Integer>());//只出不进//1
//      original_graph.get("s").put("v1",10);
//      original_graph.get("s").put("v2",10);
////        System.out.println(original_graph.get("s"));
//      original_graph.put("v1",new HashMap<String,Integer>());
//      original_graph.get("v1").put("v2",2);
//      original_graph.get("v1").put("v3",4);
//      original_graph.get("v1").put("v4",8);
//      original_graph.put("v2",new HashMap<String,Integer>());
//      original_graph.get("v2").put("v4",9);
//      original_graph.put("v3",new HashMap<String,Integer>());
//      original_graph.get("v3").put("t",10);
//      original_graph.put("v4",new HashMap<String,Integer>());
//      original_graph.get("v4").put("v3",6);
//      original_graph.get("v4").put("t",10);
//      original_graph.put("t",new HashMap<String,Integer>());//只进不出//2original_graph.get("s").put("v1",8);original_graph.get("s").put("v2",12);original_graph.put("v1",new HashMap<String,Integer>());original_graph.get("v1").put("v3",6);original_graph.get("v1").put("v4",10);original_graph.put("v2",new HashMap<String,Integer>());original_graph.get("v2").put("v1",2);original_graph.get("v2").put("v3",10);original_graph.put("v3",new HashMap<String,Integer>());original_graph.get("v3").put("t",8);original_graph.put("v4",new HashMap<String,Integer>());original_graph.get("v4").put("v3",2);original_graph.get("v4").put("t",10);original_graph.put("t",new HashMap<String,Integer>());
//      System.out.println(original_graph.get("t").isEmpty());}public void initial_residual_graph() { // 初始化构造方法和original_graph一样//1
//      residual_graph.put("s",new HashMap<String,Integer>());residual_graph.get("s").put("v1",10);
//      residual_graph.get("s").put("v2",10);residual_graph.put("v1",new HashMap<String,Integer>());
//      residual_graph.get("v1").put("v2",2);residual_graph.get("v1").put("v3",4);
//      residual_graph.get("v1").put("v4",8);residual_graph.put("v2",new HashMap<String,Integer>());
//      residual_graph.get("v2").put("v4",9);residual_graph.put("v3",new HashMap<String,Integer>());
//      residual_graph.get("v3").put("t",10);residual_graph.put("v4",new HashMap<String,Integer>());
//      residual_graph.get("v4").put("v3",6);residual_graph.get("v4").put("t",10);
//      residual_graph.put("t",new HashMap<String,Integer>());//2residual_graph.put("s",new HashMap<String,Integer>());residual_graph.get("s").put("v1",8);residual_graph.get("s").put("v2",12);residual_graph.put("v1",new HashMap<String,Integer>());residual_graph.get("v1").put("v3",6);residual_graph.get("v1").put("v4",10);residual_graph.put("v2",new HashMap<String,Integer>());residual_graph.get("v2").put("v1",2);residual_graph.get("v2").put("v3",10);residual_graph.put("v3",new HashMap<String,Integer>());residual_graph.get("v3").put("t",8);residual_graph.put("v4",new HashMap<String,Integer>());residual_graph.get("v4").put("v3",2);residual_graph.get("v4").put("t",10);residual_graph.put("t",new HashMap<String,Integer>());}//使用bfspublic void initial_level_graph() {//初始化变量level_graph = new HashMap<String, HashMap<String,Integer>>();Queue<String> queue = new LinkedList<String>();ArrayList<String> traversed_node = new ArrayList<String>();//遍历过的点HashMap<String,Integer> node_level = new HashMap<String,Integer>();node_level.put("s",0);traversed_node.add("s");String pointer;queue.offer("s");while(!queue.isEmpty()) {pointer = queue.poll();Iterator<String> iterator = residual_graph.get(pointer).keySet().iterator();while (iterator.hasNext()) {String key = iterator.next();//表示当前点pointer有连接点,但是不确定这个点是否能加入层次图if(!traversed_node.contains(key)) {if (residual_graph.get(pointer).get(key) > 0 ) { // 表示能通过node_level.put(key,node_level.get(pointer)+1);traversed_node.add(key);// 添加遍历过的节点queue.offer(key); // 这一步会把同一level的点全部加到队列中去 }         }//下面这个判断条件可以优化if (node_level.get(key) != null && node_level.get(pointer) != null) {if (node_level.get(key) > node_level.get(pointer)) {int value = residual_graph.get(pointer).get(key); //边的剩余容量// 只有容量大于0才能通过if (value > 0) {if (!level_graph.containsKey(pointer)){ // 没有这个key就要重新初始化level_graph.put(pointer,new HashMap<String,Integer>());}level_graph.get(pointer).put(key,value);}
//                      System.out.println(level_graph);}  }}}}//dfs,回溯//寻找层次图的阻塞流public void find_blocking_flow(String node) {HashMap<String,Integer> tempHashMap = level_graph.get(node);
//      System.out.println(tempHashMap);if (node == "t") {is_blocking_flow = true;ArrayList<Integer> tempArray = new ArrayList<>(residual_flow_value);Collections.sort(tempArray);augmented_value = tempArray.get(0);for (int id = 0; id < residual_flow_path.size()-1 ;id++) {level_graph.get(residual_flow_path.get(id)).replace(residual_flow_path.get(id+1), level_graph.get(residual_flow_path.get(id)).get(residual_flow_path.get(id+1))-augmented_value);}for (int id = 0; id < residual_flow_value.size() ;id++) { // 存值数组需要动态更新residual_flow_value.set(id, residual_flow_value.get(id)-augmented_value);}
//          System.out.println(level_graph);
//          System.out.println(residual_flow_path); //从起点到终点的所有通路}if (tempHashMap == null)  {// 根据层次图的处理,决定使用tempHashMap.isEmpty()还是tempHashMap == null      return;}Iterator<String> iterator = tempHashMap.keySet().iterator();while (iterator.hasNext()) {String key = iterator.next();int value = tempHashMap.get(key);if (value > 0) {residual_flow_value.add(value);residual_flow_path.add(key);
//              System.out.println(residual_flow_value);find_blocking_flow(key);
//              System.out.println(key);residual_flow_value.remove(residual_flow_value.size()-1);//去掉最后一个residual_flow_path.remove(residual_flow_path.size()-1);//去掉最后一个    }           }}public void updateResidualGraph() {// 在层次图寻找到一条阻塞流之后,更新残留网络的流量Iterator<String> iterator_1 = level_graph.keySet().iterator();while (iterator_1.hasNext()) {String key_1 = iterator_1.next();HashMap<String,Integer> tempHashMap = level_graph.get(key_1);Iterator<String> iterator_2 = tempHashMap.keySet().iterator();while(iterator_2.hasNext()) {String key_2 = iterator_2.next();int value = tempHashMap.get(key_2);residual_graph.get(key_1).replace(key_2, value);}}// 给残留图添加反向边int inversed_value = 0;Iterator<String> iterator_3 = level_graph.keySet().iterator();while(iterator_3.hasNext()) {String key_3 = iterator_3.next();// 数组迭代器不能在迭代过程中改变,所以需要有一个不变的数据结构HashMap<String,Integer> tempHashMap = level_graph.get(key_3);Iterator<String> iterator_4 = tempHashMap.keySet().iterator();while(iterator_4.hasNext()) {String key_4 = iterator_4.next();// original_graph.get(key_3).get(key_4) 和 residual_graph.get(key_3).get(key_4) 一定不是null,// 考虑到原始图没有反向边if (original_graph.get(key_3).get(key_4) != null) {inversed_value = original_graph.get(key_3).get(key_4)- residual_graph.get(key_3).get(key_4);}else {inversed_value = original_graph.get(key_4).get(key_3)- residual_graph.get(key_3).get(key_4);}           residual_graph.get(key_4).put(key_3,inversed_value);}inversed_value = 0;}// 在dinic算法中,我一开始认为没有必要构造从汇点到汇点上一层的点、源点下一层到源点的反向边了。但我后来觉得不应该。// 切记,更新的是残留图,不是层次图。}public void dinic_max_flow() {// 初始化原始的网络图initial_original_graph();// 初始化残留网络,等于原始的网络图initial_residual_graph();System.out.println("原始网络图: "+original_graph);int iteration = 0;while(true) {// 初始化残留网络的层次图iteration++;System.out.println("---------第"+iteration+"次迭代"+"---------");           initial_level_graph();System.out.println("层次图: "+level_graph);residual_flow_path.clear();residual_flow_path.add("s");// 从源点开始寻找改层次图的阻塞流,多个增广路构成阻塞流find_blocking_flow("s");System.out.println("增广后的层次图: "+level_graph);if (!is_blocking_flow) {// 一旦残留网络没办法找到阻塞流了,中止循环break;}is_blocking_flow = false;//找到之后,开始更新残留网络,并添加反向边updateResidualGraph();System.out.println("更新流量后的残留图: "+residual_graph);}System.out.println("最终的残留图: "+residual_graph);System.out.println("---------最大流---------");get_max_flow();}public void get_max_flow() {int capacity = 0;/*计算最大容量不能计算原始图源点的出度,注释掉的是错误的*/
//      HashMap<String,Integer> capacityHashMap = original_graph.get("s");
//      Iterator<String> iterator_1 = capacityHashMap.keySet().iterator();
//      while(iterator_1.hasNext()) {//          String key_1 = iterator_1.next();
//          capacity = capacity + capacityHashMap.get(key_1);
//      }Iterator<String> iterator_1 = original_graph.keySet().iterator();while(iterator_1.hasNext()) {String key_1 = iterator_1.next();HashMap<String,Integer> flowHashMap = original_graph.get(key_1);Iterator<String> iterator_2 = flowHashMap.keySet().iterator();while(iterator_2.hasNext()) {String key_2 = iterator_2.next();if (key_2 == "t") {capacity = capacity + flowHashMap.get(key_2);}}}int residual = 0;Iterator<String> iterator_3 = residual_graph.keySet().iterator();while(iterator_3.hasNext()) {String key_3 = iterator_3.next();HashMap<String,Integer> flowHashMap = residual_graph.get(key_3);Iterator<String> iterator_4 = flowHashMap.keySet().iterator();while(iterator_4.hasNext()) {String key_4 = iterator_4.next();if (key_4 == "t") {residual = residual + flowHashMap.get(key_4);}}}
//      System.out.println(capacity);maximum_flow = capacity - residual;System.out.println("最大流为: "+maximum_flow);}public static void main(String args[])  {dinic d = new dinic(); d.dinic_max_flow();}}

2、算法支撑

2.1 dinic算法

目标: 找到最大流 Maximum Flow ,公式: Flow = Capacity - Residual
1、首先,构建一个Residual graph(残留网络),初始化残留网络为原始的网络图
2、重复进行下面的三步:
 2.1 构建残留图的层次图
 2.2 寻找层次图的阻塞流
 2.3 更新残留网络(包括更新残留量、去掉残留量为0的边、添加反向边)
循环中止条件: 层次图中无法找到阻塞流

2.2 寻找阻塞流的算法

1、首先,构建一个残留网络Residual graph,初始化残留网络为原始的网络图
2、当Augmenting path(增广路)被找到时:
 2.1 在残留图中寻找增广路
 2.2 寻找增广路上最小的容量 x
 2.3 更新残留网络 residual = residual - x
循环中止条件: 层次图中无法找到增广流

3、总结

  在代码中有我进行了详细的注释,主要使用 BFS + DFS 的基础算法架构,同时根据我自己的编程习惯,采用双层字典的数据结构实现Dinic算法。
  如果觉得不错,请点个赞吧,不定期更新;如果有错误,还请批评指正,感谢!

Dinic算法寻找网络最大流的Java实现相关推荐

  1. 算法艺术——网络最大流

    女强人:http://blog.csdn.net/abcjennifer/article/details/5556455 USACO 4.2.1 Ditch 网络最大流问题算法小结 通过 USACO ...

  2. 算法---------寻找重复的子树(Java版本)

    题目描述: 给定一棵二叉树,返回所有重复的子树.对于同一类的重复子树,你只需要返回其中任意一棵的根结点即可.两棵树重复是指它们具有相同的结构以及相同的结点值.示例 1:1/ \2 3/ / \4 2 ...

  3. 【网络流】解题报告:luogu P3376 【模板】网络最大流

    题目链接: P3376 [模板]网络最大流 Dinic Dinic算法是网络流最大流的优化算法之一,每一步对原图进行分层,然后用DFS求增广路.时间复杂度是O(n^2*m),Dinic算法最多被分为n ...

  4. 【ybt金牌导航3-2-1】【luogu P3376】网络最大流【Dinic算法】

    网 络 最 大 流 网络最大流 网络最大流 题目链接:ybt金牌导航3-2-1 / luogu P3376 题目 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入 第一行包含四个正整数 ...

  5. 网络最大流的三种基础算法

    #include<iostream> #include<cstring> #include<queue> #include<cstdio> #inclu ...

  6. 最大流EK和Dinic算法

    最大流EK和Dinic算法 EK算法 最朴素的求最大流的算法. 做法:不停的寻找增广路,直到找不到为止 代码如下: @Frosero #include <cstdio> #include ...

  7. 图论 —— 网络流 —— 最大流 —— Dinic 算法

    [概述] Dinic 算法在 EK 算法的基础上进行了优化,其时间复杂度为 O(n*n*m). Dinic 在找增广路的时也是找最短增广路, 但与 EK 算法不同的是 Dinic 算法并不是每次 bf ...

  8. 网络流初步:最大流(Dinic算法)

    网络流初步:最大流 标签: 网络流 最大流 Dinic 最大流 例题 POJ****(USACO4.2.1) 在农夫约翰的农场上,每逢下雨,Bessie最喜欢的三叶草地就积聚了一潭水.这意味着草地被水 ...

  9. 最大流之Dinic 算法

    看了http://www.cnblogs.com/SYCstudio/p/7260613.html和 https://comzyh.com/blog/archives/568/两位大佬的博客 颇有收获 ...

最新文章

  1. [JAVAEE] 初识ThymeLeaf
  2. CF1012F Passports
  3. 【转】并行计算、分布式计算、集群计算和云计算
  4. JAVA_IO流四大家族(2)
  5. 编译器扩展SEH(2)
  6. sap 标准委外和工序委外_「SAP技术」SAP MM 委外加工采购流程里副产品的收货
  7. subst命令镜像虚拟磁盘指南(原创)
  8. Win7的市场份额终于超过XP了,以后可以逐渐考虑放弃ie6/7了!
  9. unity3D常见问题
  10. (王道408考研操作系统)第三章内存管理-第一节4:连续分配管理方式(单一连续、固定分区和动态分区分配)
  11. SharePoint PowerShell 批量删除遗弃视图
  12. JAVA 对于点号.的处理
  13. 解决Eclipse建Maven项目module无法转换为2.5
  14. Android GsmCellLocation.getCellLocation返回NULL
  15. [Git]git教程
  16. matlab教程课后答案肖汉光,MATLAB大学教程
  17. 嵌入式linux 面试题
  18. Java刷题面试系列习题(三)
  19. HackTheBox-Magic-Walkthrough
  20. arduino 鸿蒙,arduino入门开发案例(上)

热门文章

  1. 中国CAR-T细胞疗法成果首登Nature,我们与背后公司聊了聊技术进展|量子位·对撞派 × 邦耀生物...
  2. 读《STRENGTHNET: DEEP LEARNING-BASED EMOTION STRENGTH ASSESSMENT FOR EMOTIONAL SPEECH SYNTHESIS》
  3. ASP.NET MVC俗气的罗斯文示例代码
  4. 正则表达式验证手机号,邮箱
  5. ARGOX 力象 CP-3140L 条码打印机 B/S 打印
  6. 上位机和Arduino的通信的解决方案
  7. 深入剖析Spring Web源码(十九) - 整理的文档和日志的索引(第一版)
  8. [HNOI2004]宠物收养所 SBT
  9. 数学建模学习笔记(一):插值法
  10. 给Date日期加上时分秒