(a) 利用ford-fulkerson算法即可求出最大流和最小分割。

(b) 剩余网络为

由S可达的顶点为A、B。可达T的顶点为C。

(c) 瓶颈边有e(A,C),e(B,C)。

(d) 下图中不包含瓶颈边。

(e) 如果一条边e(u,v)是瓶颈边,首先这条边必须存在原图中,同时,在残量图中存在S到u的路径并且存在v到T的路径,所以在残量图中增加一条边e(u,v)后将使最大流的规模增加。首先在残量图中从S开始进行一次DFS求出从源点S可以到达的顶点集合W,然后在残量图的反向图中从T开始进行DFS求出可以到达T的顶点集合Y。最后遍历原图中的所有边e(u,v),若uW并且vY,则e(u,v)是一条瓶颈边。

 package org.xiu68.ch07.ex13;

 import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator; public class Ex7_17 { public static void main(String[] args) {
// TODO Auto-generated method stub
int[][] c=new int[][]{
{0,7,6,0,0,0},
{0,0,0,4,2,0},
{0,0,0,2,3,0},
{0,0,0,0,0,9},
{0,0,0,0,0,5},
{0,0,0,0,0,0}
};
String[] vexs=new String[]{"S","A","B","C","D","T"};
MGraph<String> m1=new MGraph<String>(c, vexs);
m1.fordFulkerson(0, 5);
} } class MGraph<T>{
private int[][] c; //容量矩阵
private int[][] e; //残量矩阵
private int[][] f; //当前流矩阵
private int vexNum; //顶点数量
private String[] vexs; //顶点表 public MGraph(int[][] c,String[] vexs){
this.c=c;
this.vexNum=c.length;
this.e=new int[vexNum][vexNum];
this.f=new int[vexNum][vexNum];
this.vexs=vexs; //刚开始时残量矩阵等于容量矩阵
for(int i=0;i<vexNum;i++){
System.arraycopy(c[i], 0, e[i], 0, c[i].length);
} } //fordFulkerson算法
public void fordFulkerson(int s,int t){
int[] route=new int[vexNum]; //s到t的路径数组,route[i]表示i的前一个顶点 while(bfs(s,t,route)){ //若还能找到一条路径 //寻找路径中流最小的边的大小(在残量矩阵中)
int min=Integer.MAX_VALUE;
int tail=t;
int head=route[t]; while(head!=-1){
if(e[head][tail]<min){
min=e[head][tail];
}
tail=head;
head=route[head];
} //更新当前流矩阵和残量矩阵
int tail1=t;
int head1=route[tail1];
while(head1!=-1){
//更新当前流矩阵
if(c[head1][tail1]!=0){
f[head1][tail1]+=min; //容量矩阵中存在边,增加head1到tail1的流的大小为min
}else{
f[head1][tail1]-=min; //容量矩阵中不存在边,撤销head1到tail1的流的大小为min
}
//更新残量矩阵
e[head1][tail1]-=min; //head1到tail1的流量减少min
e[tail1][head1]+=min; //tail1到head1的流量增加min tail1=head1;
head1=route[head1];
}//while
//route=new int[vexNum];
Arrays.fill(route, 0); //初始化路径数组
}//while 还能找到一条s到t的路径 //输出最大流
int maxFlow=0;
for(int i=0;i<vexNum;i++) //最大流为 当前流矩阵中 从s流出的量
maxFlow+=f[s][i];
System.out.println("最大流为:"+maxFlow); //输出最小割
System.out.print("最小割为(集合S):");
HashSet<Integer> cut=cut(s);
for(Iterator<Integer> iter=cut.iterator();iter.hasNext();){
System.out.print(vexs[iter.next()]+" ");
}
System.out.println(); //输出瓶颈边
System.out.println("瓶颈边有");
HashSet<Edge> bottleneckEdgeSet=bottleneckEdge(s,t);
for(Iterator<Edge> be=bottleneckEdgeSet.iterator();be.hasNext();){
Edge ed=be.next();
System.out.print("e("+vexs[ed.getHead()]+","+vexs[ed.getTail()]+") ");
}
} //广度优先搜索在残量图e中寻找s到t的路径
public boolean bfs(int s,int t,int[] route){
boolean[] visited=new boolean[vexNum]; //访问数组
visited[s]=true; ArrayDeque<Integer> queue=new ArrayDeque<>();
route[s]=-1; //设s的前一个顶点为-1 for(int i=0;i<vexNum;i++){
if(e[s][i]!=0 && !visited[i]){ //在残量矩阵中s到i存在一条路径
queue.add(i);
route[i]=s;
visited[i]=true;
}
} while(!queue.isEmpty()){
int middleVex=queue.poll();
if(middleVex==t){
return true;
}else{
for(int i=0;i<vexNum;i++){
if(e[middleVex][i]!=0 && !visited[i]){
queue.add(i);
route[i]=middleVex;
visited[i]=true;
}
}
}
}//while
return false;
} //求最小割
//在残量矩阵中,从s开始做一次搜索,从s能达到的所有的顶点都属于集合S
public HashSet<Integer> cut(int s){
boolean[] visited=new boolean[vexNum];
HashSet<Integer> cut=new HashSet<>(); //保存最小割,集合S
dfs(e,visited,cut,s);
return cut;
}
//求瓶颈边
public HashSet<Edge> bottleneckEdge(int s,int t){ HashSet<Integer> w=new HashSet<>(); //从顶点S可以到达的顶点集合
boolean[] visitedS=new boolean[vexNum];
dfs(e,visitedS,w,s); //从顶点s开始进行深度优先搜索,求从顶点S可以到达的顶点集合 //求残量图的反向图
int[][] reverseE=new int[vexNum][vexNum];
for(int i=0;i<vexNum;i++){
for(int j=i+1;j<vexNum;j++){
reverseE[i][j]=e[j][i];
reverseE[j][i]=e[i][j];
}
}
HashSet<Integer> y=new HashSet<>(); //从顶点S可以到达的顶点集合
boolean[] visitedT=new boolean[vexNum];
dfs(reverseE,visitedT,y,t); //从顶点t开始进行深度优先搜索,求从顶点T可以到达的顶点集合 HashSet<Edge> bottleneckEdgeSet=new HashSet<>();
//遍历原图中的所有边e(u,v),求u属于集合w,v属于集合y的边
for(int i=0;i<vexNum;i++){
for(int j=0;j<vexNum;j++){
if(c[i][j]!=0 && w.contains(i) && y.contains(j)){
bottleneckEdgeSet.add(new Edge(i,j));
}
}
}
return bottleneckEdgeSet;
}
//深度优先搜索,记录搜索到的所有顶点
private void dfs(int[][] edges,boolean[] visited,HashSet<Integer> set,int v){
set.add(v);
visited[v]=true;
for(int i=0;i<vexNum;i++){
if(edges[v][i]!=0 && !visited[i]){
dfs(edges,visited,set,i);
}
}
}
} class Edge{
private int head; //边的头
private int tail; //边的尾
public Edge(int head, int tail) {
super();
this.head = head;
this.tail = tail;
}
public int getHead() {
return head;
}
public void setHead(int head) {
this.head = head;
}
public int getTail() {
return tail;
}
public void setTail(int tail) {
this.tail = tail;
} }

Ex 7_17 考虑如下的网络(其中数字为对应边的容量)...第十三次作业的更多相关文章

  1. Pytorch CNN网络MNIST数字识别 [超详细记录] 学习笔记(三)

    目录 1. 准备数据集 1.1 MNIST数据集获取: 1.2 程序部分 2. 设计网络结构 2.1 网络设计 2.2 程序部分 3. 迭代训练 4. 测试集预测部分 5. 全部代码 1. 准备数据集 ...

  2. 2017-2018-2 20179207 《网络攻防技术》第十三周作业 python3实现SM234算法

    国密算法SM234 的python3实现 国家标准 GM/T 0002-2012 <SM4分组密码算法> GM/T 0003.1-2012 <SM2椭圆曲线公钥密码算法 第1部分:总 ...

  3. P2602 [ZJOI2010]数字计数&P1239 计数器&P4999 烦人的数学作业

    P2602 [ZJOI2010]数字计数 题解 DFS 恶心的数位DP 对于这道题,我们可以一个数字一个数字的求 也就是分别统计区间 [ L , R ] 内部数字 i 出现的次数 (0<=i&l ...

  4. 集美大学网络1413第十三次作业成绩(团队八) -- 第二次项目冲刺(Beta阶段)

    题目: 团队作业8--第二次项目冲刺(Beta阶段) 团队作业8-成绩:  团队/分值 新加入成员 角色 技术特点 改善的功能. 原因. bug 新增功能. 方法. 如何实现 团队分工改进. 原因 改 ...

  5. Ex 7_21 在一个流网络中,一条边被称为是临界的...第十三次作业

    如果原图中的一条边e(u,v)是临界边,则在求解最大流的过程中这条边的流量将会被占满,即在残量图中只存在反向边e(v,u),不存在正向边e(u,v).但是残量图中并不是所有的只存在反向边的顶点对之间的 ...

  6. iOS 实时监听app的网络连接状态

    实际iOS开发中,在网络通信中我们大部分使用第三方(只谈短链),譬如 AFNetworking.ASIHttpRequest(这个停更了,想必现在没多少人用),swift的 Alamofire 等. ...

  7. 主流芯片解决方案Ambarella的高清网络摄像机、德州仪器和控制海思

    (本文由四川艾普作为数码科技有限公司 苏斌.范清华 收集) 高清网络视频监控发展到今天.正的高清时代.诸多有实力的高清摄像机厂家的产品线也逐渐完好起来,高清网络视频监控的配套产品有更加丰富和成熟.与此 ...

  8. 网络配置:IP+NETMASK+GATEWAY+DNS

    1.  IP IP地址(英语:Internet Protocol Address)是一种在Internet上的给主机编址的方式,也称为网际协议地址.常见的IP地址,分为IPv4与IPv6两大类. IP ...

  9. 理解 HTTPS 工作原理(公钥、私钥、签名、数字证书、加密、认证)(转)

    本文摘录参考: 细说 CA 和证书(主要讲解 CA 的使用) 数字签名是什么?(简单理解原理) 深入浅出 HTTPS 工作原理(深入理解原理) HTTP 协议由于是明文传送,所以存在三大风险: 1.被 ...

随机推荐

  1. forEach、for in、for of 三者对比

    forEach forEach专门用来循环数组,可以直接取到元素,同时也可以取到index值 存在局限性,不能continue跳过或者break终止循环,没有返回值,不能return let arr ...

  2. 爬虫基础02-day24

    写在前面 上课第24天,打卡: 努力不必让全世界知道: s16/17爬虫2 内容回顾: 1. Http协议 Http协议:GET / http1.1/r/n...../r/r/r/na=1 TCP协议 ...

  3. Android 全屏设置和禁止横屏竖屏切换

    android:screenOrientation="portrait" #禁止屏幕横竖切换,portrait为纵向,landscape为横向

  4. 二、linux IO 编程---系统调用和POSIX标准和标准IO

    2.1 系统调用 2.1.1 概念 所谓系统调用(system call)是指曹错系统提供给用户程序的一组“特殊”接口,用户程序可以通过这组“特殊”接口来获得操作系统内核提供的特殊服务. 应用程序可以 ...

  5. /*+ hint*/用法,该如何解决

    /*+ use_hash(b, a)*/用法SELECT /*+ use_hash(b, a)*/  1,  NVL(b.AgentWorkGroup, ' '),  ................ ...

  6. 第25月第17天 django rest framwork authentication /tmp/mysql.sock

    1.authentication https://www.django-rest-framework.org/api-guide/authentication/#authentication 2.dj ...

  7. js公共弹出窗插件

    /*错误提示框*/ var wr = function() { var wrap = '<div class="wrapBox opacity"> </div&g ...

  8. border-radius图解

    自己看了理解的border-radius: 设置参数: 100*100的正方形,第一个:border-top-left-radius:100px 100px,即圆的半径为100px.圆弧与上和左bor ...

  9. 在github上创建自己的项目

    使用过很多次github 但一直是把别人的项目clone下来,并没有自己创建过项目.所以记录一下~ 首先,创建一个仓库 填写工程名之后就创建好啦 然后clone代码到本地 就和正常的使用完全一样啦 ~ ...

  10. 高性能缓存Caffeine

    1. Caffeine 为我们提供了三种填充策略:手动.同步和异步 2. Caffeine提供三类驱逐策略:基于大小(size-based),基于时间(time-based)和基于引用(referen ...