目录

1 问题描述

2 解决方案

 


1 问题描述

在最大流有多组解时,给每条边在附上一个单位费用的量,问在满足最大流时的最小费用是多少?


2 解决方案

下面代码所使用的测试数据如下图:

具体代码如下:

package com.liuzhen.practice;

import java.util.ArrayList;
import java.util.Scanner; public class Main {
public static int MAX = 1000;
public static int n; //图中顶点数目
public static boolean[] used = new boolean[MAX]; //判断顶点是否在队列中
public static int[] pre = new int[MAX]; //记录最短增广路径中相应节点的前节点
public static int[] distance = new int[MAX]; //记录源点到图中其他所有顶点的最短距离
public static int[] capacity = new int[MAX]; //用于记录遍历图每一次得到增广路径的流量
public static ArrayList<edge>[] map; //图的邻接表
//表示图中边信息内部类
static class edge {
public int from; //边的起点
public int to; //边的终点
public int cap; //边的容量
public int cost; //边的费用 public edge(int from, int to, int cap, int cost) {
this.from = from;
this.to = to;
this.cap = cap;
this.cost = cost;
}
}
//输入给定图数据
@SuppressWarnings("unchecked")
public void init() {
Scanner in = new Scanner(System.in);
n = in.nextInt();
int k = in.nextInt(); //给定图的边数目
map = new ArrayList[n];
for(int i = 0;i < n;i++)
map[i] = new ArrayList<edge>();
for(int i = 0;i < k;i++) {
int from = in.nextInt();
int to = in.nextInt();
int cap = in.nextInt();
int cost = in.nextInt();
map[from].add(new edge(from, to, cap, cost)); //正向边
map[to].add(new edge(to, from, 0, -cost)); //反向边
}
} //寻找顶点start到顶点end的最短路径(PS:即费用最少的一条增广路径)
public boolean spfa(int start, int end) {
int[] count = new int[n];
for(int i = 0;i < n;i++) {
used[i] = false;
pre[i] = -1;
distance[i] = Integer.MAX_VALUE;
capacity[i] = Integer.MAX_VALUE;
}
used[start] = true;
pre[start] = start;
distance[start] = 0;
count[start]++;
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(start);
while(!list.isEmpty()) {
int index = list.get(0);
list.remove(0);
used[index] = false;
for(int i = 0;i < map[index].size();i++) {
edge temp = map[index].get(i);
if(temp.cap > 0 && distance[temp.to] > distance[index] + temp.cost) {
//记录顶点start到图中其它顶点之间的最短费用距离
distance[temp.to] = distance[index] + temp.cost;
pre[temp.to] = index;
//记录增广路径能够流通的最大流量
capacity[temp.to] = Math.min(capacity[index], temp.cap);
if(!used[temp.to]) {
used[temp.to] = true;
list.add(temp.to);
count[temp.to]++;
if(count[temp.to] > n) //用于判断图中是否有负环
return false;
}
}
}
}
if(distance[end] != Integer.MAX_VALUE && pre[end] != -1)
return true;
return false;
} public int getResult() {
init(); //输入给定图数据
int minCost = 0;
int start = 0; //把源点设置为顶点0
int end = n - 1; //把汇点设置为顶点n - 1
while(true) {
if(spfa(start, end) == false)
break;
System.out.println("增广路径增量:"+capacity[end]+", 费用流:"+distance[end]);
minCost += distance[end] * capacity[end];
int last = end;
int begin = end;
System.out.print("汇点出发");
while(begin != start) {
last = begin;
begin = pre[last];
int i = 0, j = 0;
System.out.print("——>"+last);
for(;i < map[begin].size();i++) {
if(map[begin].get(i).to == last)
break;
}
map[begin].get(i).cap -= capacity[end]; //正向边剩余流量减少
for(;j < map[last].size();j++) {
if(map[last].get(j).to == begin)
break;
}
map[last].get(j).cap += capacity[end]; //反向边剩余流量增加
}
System.out.println("——>"+begin);
}
return minCost;
} public static void main(String[] args) {
Main test = new Main();
int result = test.getResult();
System.out.println(result);
}
}

运行结果:

6
7
0 1 2 1
0 3 3 2
1 2 5 5
1 4 3 4
2 5 2 10
3 2 1 3
4 5 4 7
增广路径增量:2, 费用流:12
汇点出发——>5——>4——>1——>0
增广路径增量:1, 费用流:15
汇点出发——>5——>2——>3——>0
39

参考资料:

1. 最小费用最大流详解与模板

算法笔记_140:最小费用最大流问题(Java)的更多相关文章

  1. Java实现最小费用最大流问题

    1 问题描述 在最大流有多组解时,给每条边在附上一个单位费用的量,问在满足最大流时的最小费用是多少? 2 解决方案 下面代码所使用的测试数据如下图: package com.liuzhen.pract ...

  2. 算法模板——Dinic最小费用最大流

    实现功能:输入M,N,S,T:接下来M行输入M条弧的信息(包括起点,终点,流量,单位费用):实现功能是求出以S为源点,T为汇点的网络最大流的最小费用 其实相当的像Dinic最大流呐= = 还是spfa ...

  3. 算法笔记_023:拓扑排序(Java)

    目录 1 问题描述 2 解决方案 2.1 基于减治法实现 2.2 基于深度优先查找实现 1 问题描述 给定一个有向图,求取此图的拓扑排序序列. 那么,何为拓扑排序? 定义:将有向图中的顶点以线性方式进 ...

  4. poj3422 Kaka's Matrix Travels(最小费用最大流问题)

    /* poj3422 Kaka's Matrix Travels 不知道 k次 dp做为什么不对??? 看了大牛的代码,才知道还可以这样做! 开始没有理解将a 和 a‘ 之间建立怎样的两条边,导致程序 ...

  5. 算法笔记_132:最大流量问题(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 何为最大流量问题? 给定一个有向图,并为每一个顶点设定编号为0~n,现在求取从顶点0(PS:也可以称为源点)到顶点n(PS:也可以称为汇点)后,顶点 ...

  6. 算法笔记_228:信用卡号校验(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 当你输入信用卡号码的时候,有没有担心输错了而造成损失呢?其实可以不必这么担心,因为并不是一个随便的信用卡号码都是合法的,它必须通过Luhn算法来验证 ...

  7. 算法笔记_217:黑洞数(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 任意一个5位数,比如:34256,把它的各位数字打乱,重新排列,可以得到一个最大的数:65432,一个最小的数23456.求这两个数字的差,得:41 ...

  8. 算法笔记_178:历届试题 邮局(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 问题描述 C村住着n户村民,由于交通闭塞,C村的村民只能通过信件与外界交流.为了方便村民们发信,C村打算在C村建设k个邮局,这样每户村民可以去离自己 ...

  9. 算法笔记_138:稳定婚姻问题(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 何为稳定婚姻问题? 有一个男士的集合Y = {m1,m2,m3...,mn}和一个女士的计划X = {n1,n2,n3,...,nn}.每一个男士有 ...

随机推荐

  1. ubuntu16.04.2安装完后重启报错[sda] Assuming drive cache: write through

    原因:检测主机的物理连接线,发生问题时"已连接"未勾选,重启的时候找不到iso文件 解决办法:勾选"已连接",重启机器成功

  2. [BZOJ4651][NOI2016]网格(Tarjan)

    下面直接给出结论,相关证明见官方题解. 1.若跳蚤数不超过1或仅有两只跳蚤且相邻,则答案为-1. 2.若跳蚤形成的连通块个数大于1,则答案为0. 3.若跳蚤之间建图存在割点,则答案为1. 4.否则为2 ...

  3. 2018 计算之道初赛第二场 阿里巴巴的手机代理商(困难)(反向可持久化Trie)

    阿里巴巴的手机代理商(困难) 阿里巴巴的手机代理商正在研究 infra 输入法的新功能.他们需要分析单词频率以改进用户输入法的体验.于是需要你在系统内核里面写一个 API. API 有如下功能: 添加 ...

  4. HDU 5301 Buildings 数学

    Buildings 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5301 Description Your current task is to m ...

  5. leetcode132. Palindrome Partitioning II

    leetcode132. Palindrome Partitioning II 题意: 给定一个字符串s,分区使分区的每个子字符串都是回文. 返回对于s的回文分割所需的最小削减. 例如,给定s =&q ...

  6. Windows xp/2003 中安装虚拟网卡 Microsoft Loopback Adapter

    方法 1 (命令行下安装)devcon.exe install %windir%\inf\netloop.inf *msloop 类似于以下输出表示安装成功: Device node created. ...

  7. Dual-voltage regulator meets USB-power needs

    This Design Idea stems from the limited availability of IC voltage regulators that can meet key USB- ...

  8. C语言中常用计时方法总结

    转自:http://blog.csdn.net/fz_ywj/article/details/8109368 C语言中常用计时方法总结 1. time() 头文件:time.h 函数原型:time_t ...

  9. JAVA 文本 TXT 操作工具类

    import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; imp ...

  10. Birt中实现字段拆分为表的还有一种方法

    来源:     http://developer.actuate.com/community/forum/index.php? /topic/36204-split-data-row/. 将字段拆分为 ...