学习地址

目录

  • 第 31 天: 整数矩阵及其运算
  • 第 32 天: 图的连通性检测
  • 第 33 天: 图的广度优先遍历
  • 第 34 天: 图的深度优先遍历
  • 第 35 天: 图的 m 着色问题
  • 第 36 天: 邻连表
  • 第 37 天: 十字链表
  • 第 38 天: Dijkstra 算法与 Prim 算法
  • 第 39 天: 关键路径
  • 第 40 天: 小结

第 31 天: 整数矩阵及其运算

矩阵在前十天已经写过相关运算。

今天加了一点新东西:
1、用 this 调用其它的构造方法以减少冗余代码
2、Exception 的抛出与捕获机制:

1 异常的概念
“exception”顾名思义,就是“我对此感到意外”的意思,在程序中可以强制编译器来处理程序运行中的发生的并非由程序本身所造成的错误,这个处理方法在java中就叫做异常捕获,而这些并非程序本身产生的错误就叫做“异常”。
2 基本异常
举一个抛出异常的简单例子,对于对像引用t,传给你的时候可能没有初始化,那么在使用这个对象调用其方法前可以先对它进行检查,像这样:
if(t==null)
throws new NullPointerException();
这就是抛出了一个异常,那么在当前环境下就不必担心这个可能出现的空指针异常了,它将在别的地方获得处理。使用异常处理机制的好处就是异常允许我们强制程序停止运行,并告诉我们出现了什么问题。或者强制程序处理问题,并返回稳定状态。
3 如何捕获异常
如果方法内部出现了异常,这个方法将在抛出异常时结束,如果不希望该方法就此结束,就可以设置一个try代码块,在这个try代码块中尝试调用方法,结果如下:
try{
//要尝试运行的代码
}
4 异常处理程序
如果要将抛出的异常进行恰当的处理,就得准备相应的处理程序,异常处理程序紧跟在try代码块之后,以关键字catch表示:
try{
//要尝试运行的代码
}catch(){
//处理该异常的代码
}
(关于catch语句的异常类型:如果是catch语句的异常类型是CapacityToolException的父类,那么程序也回进入到catch语句中。)

矩阵的三种构造方法:

//1
public IntMatrix(int paraRows, int paraColumns) {data = new int[paraRows][paraColumns];
}//2
public IntMatrix(int[][] paraMatrix) {data = new int[paraMatrix.length][paraMatrix[0].length];for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[0].length; j++) {data[i][j] = paraMatrix[i][j];}}
}//3
public IntMatrix(IntMatrix paraMatrix) {this(paraMatrix.getData());
}

矩阵加法:

public void add(IntMatrix paraMatrix) throws Exception {int[][] tempData = paraMatrix.getData();if (data.length != tempData.length) {throw new Exception("Cannot add matrices. Rows not match: " + data.length + " vs. "+ tempData.length + ".");}if (data[0].length != tempData[0].length) {throw new Exception("Cannot add matrices. Rows not match: " + data[0].length + " vs. "+ tempData[0].length + ".");}for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[0].length; j++) {data[i][j] += tempData[i][j];}}
}public static IntMatrix add(IntMatrix paraMatrix1, IntMatrix paraMatrix2) throws Exception {IntMatrix resultMatrix = new IntMatrix(paraMatrix1);resultMatrix.add(paraMatrix2);return resultMatrix;
}

矩阵乘法:

public static IntMatrix multiply(IntMatrix paraMatrix1, IntMatrix paraMatrix2)throws Exception {int[][] tempData1 = paraMatrix1.getData();int[][] tempData2 = paraMatrix2.getData();if (tempData1[0].length != tempData2.length) {throw new Exception("Cannot multiply matrices: " + tempData1[0].length + " vs. "+ tempData2.length + ".");}int[][] resultData = new int[tempData1.length][tempData2[0].length];for (int i = 0; i < tempData1.length; i++) {for (int j = 0; j < tempData2[0].length; j++) {for (int k = 0; k < tempData1[0].length; k++) {resultData[i][j] += tempData1[i][k] * tempData2[k][j];}}} IntMatrix resultMatrix = new IntMatrix(resultData);return resultMatrix;
}

矩阵两种运算运行结果:

第 32 天: 图的连通性检测

令图的连通矩阵为M,若矩阵中第i行第j列元素为0,则表示i不可到达j,要知道图的连通性,则需计算M0+M1+M2+…+Mn-1得到的矩阵中是否有非零元素,如果有就不连通,否则是连通的。其中M0是单位矩阵。
代码:

package tu;
import tu.IntMatrix;public class Graph {IntMatrix connectivityMatrix;public Graph(int paraNumNodes) {connectivityMatrix = new IntMatrix(paraNumNodes, paraNumNodes);}public Graph(int[][] paraMatrix) {connectivityMatrix = new IntMatrix(paraMatrix);}public String toString() {String resultString = "This is the connectivity matrix of the graph.\r\n"+ connectivityMatrix;return resultString;}public boolean getConnectivity() throws Exception {//初始化单位矩阵IntMatrix tempConnectivityMatrix = IntMatrix.getIdentityMatrix(connectivityMatrix.getData().length);//初始化矩阵M1IntMatrix tempMultipliedMatrix = new IntMatrix(connectivityMatrix);//计算for (int i = 0; i < connectivityMatrix.getData().length - 1; i++) {// M_a = M_a + M^ktempConnectivityMatrix.add(tempMultipliedMatrix);// M^ktempMultipliedMatrix = IntMatrix.multiply(tempMultipliedMatrix, connectivityMatrix);}//检查连通性System.out.println("The connectivity matrix is: " + tempConnectivityMatrix);int[][] tempData = tempConnectivityMatrix.getData();for (int i = 0; i < tempData.length; i++) {for (int j = 0; j < tempData.length; j++) {if (tempData[i][j] == 0) {System.out.println("Node " + i + " cannot reach " + j);return false;}}}return true;}public static void getConnectivityTest() {//测试无向图int[][] tempMatrix = { { 0, 1, 0 }, { 1, 0, 1 }, { 0, 1, 0 } };Graph tempGraph2 = new Graph(tempMatrix);System.out.println(tempGraph2);boolean tempConnected = false;try {tempConnected = tempGraph2.getConnectivity();} catch (Exception ee) {System.out.println(ee);}System.out.println("Is the graph connected? " + tempConnected);//测试有向图//去掉一条弧形成有向图tempGraph2.connectivityMatrix.setValue(1, 0, 0);tempConnected = false;try {tempConnected = tempGraph2.getConnectivity();} catch (Exception ee) {System.out.println(ee);}System.out.println("Is the graph connected? " + tempConnected);}public static void main(String args[]) {System.out.println("Hello!");Graph tempGraph = new Graph(3);System.out.println(tempGraph);getConnectivityTest();}
}

分别测试了无向图和有向图的连通性:

第 33 天: 图的广度优先遍历

广度优先遍历(BFS)类似于树的层次遍历。

广度优先遍历图解:

如图所示,假设A为起点,A入队,先访问A,A出队,然后访问与A相连的未访问过的相邻的点,B,C,D入队,再访问B,B出队,与B相邻且相连的未访问过的点是E,E入队,再访问C,C出队,C相邻且相连的点有D,E,F,但是D和E都已访问过,所以只有F入队,再访问D,D出队,与G相邻且相连的未放过的只有G,G入队,然后访问E…直到所有元素出队。

代码:

public String breadthFirstTraversal(int paraStartIndex) {CircleObjectQueue tempQueue = new CircleObjectQueue();String resultString = "";int tempNumNodes = connectivityMatrix.getRows();boolean[] tempVisitedArray = new boolean[tempNumNodes];tempVisitedArray[paraStartIndex] = true;//初始化队列tempVisitedArray[paraStartIndex] = true;resultString += paraStartIndex;tempQueue.enqueue(new Integer(paraStartIndex));//从起点开始广度遍历图int tempIndex;Integer tempInteger = (Integer)tempQueue.dequeue();while (tempInteger != null) {tempIndex = tempInteger.intValue();//将所有未访问的相邻点入队for (int i = 0; i < tempNumNodes; i ++) {if (tempVisitedArray[i]) {continue; //已经访问过的不管}if (connectivityMatrix.getData()[tempIndex][i] == 0) {continue; //没有相连}//入队前访问点tempVisitedArray[i] = true;resultString += i;tempQueue.enqueue(new Integer(i));}//取出队首元素tempInteger = (Integer)tempQueue.dequeue();}return resultString;
}public static void breadthFirstTraversalTest() {//测试无向图int[][] tempMatrix = { { 0, 1, 1, 0 }, { 1, 0, 0, 1 }, { 1, 0, 0, 1}, { 0, 1, 1, 0} };Graph tempGraph = new Graph(tempMatrix);System.out.println(tempGraph);String tempSequence = "";try {tempSequence = tempGraph.breadthFirstTraversal(2);} catch (Exception ee) {System.out.println(ee);}System.out.println("The breadth first order of visit: " + tempSequence);
}

BFS结果:

第 34 天: 图的深度优先遍历

深度优先遍历(dfs):
从图中某顶点v出发:
(1)访问顶点v;
(2)依次从v的未被访问的邻接点出发,对图进行深度优先遍历;直至图中和v有路径相通的顶点都被访问;
(3)若此时图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止。

以昨天的图为例:
假设A为起点,访问A相邻的未访问的点B,再访问B的相邻未访问点E,然后是C、D、G、F。

代码:

public String depthFirstTraversal(int paraStartIndex) {ObjectStack tempStack = new ObjectStack();String resultString = "";int tempNumNodes = connectivityMatrix.getRows();boolean[] tempVisitedArray = new boolean[tempNumNodes];tempVisitedArray[paraStartIndex] = true;//初始化栈tempVisitedArray[paraStartIndex] = true;resultString += paraStartIndex;tempStack.push(new Integer(paraStartIndex));System.out.println("Push " + paraStartIndex);System.out.println("Visited " + resultString);//访问图中的其他点int tempIndex = paraStartIndex;int tempNext;Integer tempInteger;while (true){//找到一个未访问的邻点tempNext = -1;for (int i = 0; i < tempNumNodes; i ++) {if (tempVisitedArray[i]) {continue; //已访问过的跳过}if (connectivityMatrix.getData()[tempIndex][i] == 0) {continue; //不是相邻的}//Visit this one.tempVisitedArray[i] = true;resultString += i;tempStack.push(new Integer(i));System.out.println("Push " + i);tempNext = i;break;}if (tempNext == -1) {//没有未访问的邻点则回溯if (tempStack.isEmpty()) {break;}tempInteger = (Integer)tempStack.pop();System.out.println("Pop " + tempInteger);tempIndex = tempInteger.intValue();} else {tempIndex = tempNext;}}return resultString;
}public static void depthFirstTraversalTest() {//测试一个无向图int[][] tempMatrix = { { 0, 1, 1, 0 }, { 1, 0, 0, 1 }, { 1, 0, 0, 0}, { 0, 1, 0, 0} };Graph tempGraph = new Graph(tempMatrix);System.out.println(tempGraph);String tempSequence = "";try {tempSequence = tempGraph.depthFirstTraversal(0);} catch (Exception ee) {System.out.println(ee);}System.out.println("The depth first order of visit: " + tempSequence);
}

dfs结果:

第 35 天: 图的 m 着色问题

图的m-着色判定问题——给定无向连通图G和m种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色,是否有一种着色法使G中任意相邻的2个顶点着不同颜色?

当涂完一条路线的颜色,回溯(return 返回上一层)

public void coloring(int paraNumColors) {//初始化int tempNumNodes = connectivityMatrix.getRows();int[] tempColorScheme = new int[tempNumNodes];Arrays.fill(tempColorScheme, -1);coloring(paraNumColors, 0, tempColorScheme);
}public void coloring(int paraNumColors, int paraCurrentNumNodes, int[] paraCurrentColoring) {//初始化int tempNumNodes = connectivityMatrix.getRows();System.out.println("coloring: paraNumColors = " + paraNumColors + ", paraCurrentNumNodes = "+ paraCurrentNumNodes + ", paraCurrentColoring" + Arrays.toString(paraCurrentColoring));//涂完了所有颜色,回溯if (paraCurrentNumNodes >= tempNumNodes) {System.out.println("Find one:" + Arrays.toString(paraCurrentColoring));return;}//尝试所有可能的颜色for (int i = 0; i < paraNumColors; i++) {paraCurrentColoring[paraCurrentNumNodes] = i;if (!colorConflict(paraCurrentNumNodes + 1, paraCurrentColoring)) {coloring(paraNumColors, paraCurrentNumNodes + 1, paraCurrentColoring);}}
}public boolean colorConflict(int paraCurrentNumNodes, int[] paraColoring) {for (int i = 0; i < paraCurrentNumNodes - 1; i++) {if (connectivityMatrix.getValue(paraCurrentNumNodes - 1, i) == 0) {continue;}if (paraColoring[paraCurrentNumNodes - 1] == paraColoring[i]) {return true;}}return false;
}public static void coloringTest() {int[][] tempMatrix = { { 0, 1, 1, 0 }, { 1, 0, 0, 1 }, { 1, 0, 0, 0 }, { 0, 1, 0, 0 } };Graph tempGraph = new Graph(tempMatrix);tempGraph.coloring(3);
}

第 36 天: 邻连表

图的压缩存储,每一行数据用一个单链表存储。

如下图:

图的邻接表表示:该邻接表里存储了相邻节点和到该节点距离以及next指针域

代码:

class NeighborNode {int data;NeighborNode next;public NeighborNode(int data) {this.data = data;next = null;}}int numNodes;NeighborNode[] headers;public NeighborList(int[][] paraMatrix) {numNodes = paraMatrix.length;NeighborNode tpNode;headers = new NeighborNode[numNodes];//连接每个节点的相邻点for (int i = 0; i < numNodes; i++) {headers[i] = new NeighborNode(i);tpNode = headers[i];for (int j = 0; j < numNodes; j++) {if (paraMatrix[i][j] == 0) {continue;}tpNode.next = new NeighborNode(j);tpNode = tpNode.next;}}}public String toString() {String resString = "NeighborList: \n";NeighborNode tpNode;for (int i = 0; i < numNodes; i++) {tpNode = headers[i];while (tpNode.next != null) {resString += tpNode.data + "->";tpNode = tpNode.next;}resString += tpNode.data + "\n";}return resString;}//bfspublic String breadthFirstTraversal(int paraStartIndex) {CircleObjectQueue tpQueue = new CircleObjectQueue();String resString = "";boolean[] tpVisitedArray = new boolean[numNodes];tpVisitedArray[paraStartIndex] = true;resString += paraStartIndex;tpQueue.enqueue(paraStartIndex);//遍历节点int tpIndex;Integer tempInteger = (Integer) tpQueue.dequeue();NeighborNode tpNode;while (tempInteger != null) {tpIndex = tempInteger.intValue();tpNode = headers[tpIndex];while (tpNode.next != null) {tpNode = tpNode.next;if (tpVisitedArray[tpNode.data]) {continue;}tpQueue.enqueue(tpNode.data);tpVisitedArray[tpNode.data] = true;resString += tpNode.data;}tempInteger = (Integer) tpQueue.dequeue();}return resString;}public static void breadthFirstTraversalTest() {//测试无向图int[][] tempMatrix = {{0, 1, 1, 0}, {1, 0, 0, 1}, {1, 0, 0, 1}, {0, 1, 1, 0}};NeighborList tpNeighborList = new NeighborList(tempMatrix);System.out.println(tpNeighborList);String tempSequence = "";try {tempSequence = tpNeighborList.breadthFirstTraversal(2);} catch (Exception e) {System.out.println(e);}System.out.println("The breadth first order of visit: " + tempSequence);}//dfspublic String depthFirstTraversal(int paraStartIndex) {ObjectStack tpStack = new ObjectStack();String resString = "";boolean[] tpVisitedArray = new boolean[numNodes];tpVisitedArray[paraStartIndex] = true;NeighborNode tpNode = headers[paraStartIndex];resString += paraStartIndex;tpStack.push(tpNode);int num = 1;while (num < numNodes) {while (tpNode.next != null && tpVisitedArray[tpNode.next.data]) {tpNode = tpNode.next;}//回溯if (tpNode.next == null) {tpNode = (NeighborNode) tpStack.pop();continue;}resString += tpNode.next.data;tpStack.push(tpNode.next);tpVisitedArray[tpNode.next.data] = true;tpNode = headers[tpNode.next.data];num++;}return resString;}public static void depthFirstTraversalTest() {//测试无向图int[][] tempMatrix = {{0, 1, 1, 0}, {1, 0, 0, 1}, {1, 0, 0, 0}, {0, 1, 0, 0}};NeighborList tpNeighborList = new NeighborList(tempMatrix);System.out.println(tpNeighborList);String tempSequence = "";try {tempSequence = tpNeighborList.depthFirstTraversal(0);} catch (Exception ee) {System.out.println(ee);}System.out.println("The depth first order of visit: " + tempSequence);}

第 37 天: 十字链表

十字链表(Orthogonal List)是有向图的另一种链式存储结构。该结构可以看成是将有向图的邻接表和逆邻接表结合起来得到的。用十字链表来存储有向图,可以达到高效的存取效果。

class OrthogonalNode {int row;int column;//出入节点OrthogonalNode nextOut;OrthogonalNode nextIn;public OrthogonalNode(int row, int column) {this.row = row;this.column = column;nextIn = null;nextOut = null;}
}int numNodes;
OrthogonalNode[] headers;public OrthogonalList(int[][] paraMatrix) {numNodes = paraMatrix.length; //初始化OrthogonalNode tpPreNode, tpNode;headers = new OrthogonalNode[numNodes];//连接出节点for (int i = 0; i < numNodes; i++) {headers[i] = new OrthogonalNode(i, -1);tpPreNode = headers[i];for (int j = 0; j < numNodes; j++) {if (paraMatrix[i][j] == 0) {continue;}tpNode = new OrthogonalNode(i, j);tpPreNode.nextOut = tpNode;tpPreNode = tpNode;}}//连接入节点OrthogonalNode[] tpColumnNodes = new OrthogonalNode[numNodes];for (int i = 0; i < numNodes; i++) {tpColumnNodes[i] = headers[i];}for (int i = 0; i < numNodes; i++) {tpNode = headers[i].nextOut;while(tpNode!=null){tpColumnNodes[tpNode.column].nextIn = tpNode;tpColumnNodes[tpNode.column] = tpNode;tpNode = tpNode.nextOut;}}
}public String toString() {String resultString = "Out arcs: \n";OrthogonalNode tempNode;for (int i = 0; i < numNodes; i++) {tempNode = headers[i].nextOut;while (tempNode != null) {resultString += " (" + tempNode.row + ", " + tempNode.column + ")";tempNode = tempNode.nextOut;}resultString += "\r\n";}resultString += "\r\nIn arcs: \n";for (int i = 0; i < numNodes; i++) {tempNode = headers[i].nextIn;while (tempNode != null) {resultString += " (" + tempNode.row + ", " + tempNode.column + ")";tempNode = tempNode.nextIn;}resultString += "\r\n";}return resultString;
}public static void main(String args[]) {int[][] tempMatrix = { { 0, 1, 0, 0 }, { 0, 0, 0, 1 }, { 1, 0, 0, 0 }, { 0, 1, 1, 0 } };OrthogonalList tempList = new OrthogonalList(tempMatrix);System.out.println("The data are:\r\n" + tempList);
}

第 38 天: Dijkstra 算法与 Prim 算法

迪杰斯特拉(Dijkstra)算法是单源最短路径算法,用于计算一个节点到其他节点的最短路径。
它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止。


1.指定一个节点,例如要计算 ‘A’ 到其他节点的最短路径
2.引入两个集合(S、U),S集合包含已求出的最短路径的点(以及相应的最短长度),U集合包含未求出最短路径的点(以及A到该点的路径,如上图所示,A->C由于没有直接相连 初始时为∞)
3.初始化两个集合,S集合初始时 只有当前要计算的节点,A->A = 0
4.U集合初始时为 A->B = 4, A->C = ∞, A->D = 2, A->E = ∞
从U集合中找出路径最短的点,加入S集合,例如 A->D = 2
5.更新U集合路径,if ( ‘D 到 B,C,E 的距离’ + ‘AD 距离’ < ‘A 到 B,C,E 的距离’ ) 则更新U
6.循环执行 4、5 两步骤,直至遍历结束,得到A 到其他节点的最短路径

prim算法:
1.输入:一个加权连通图,其中顶点集合为V,边集合为E;
2.初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;
3.重复下列操作,直到Vnew = V:
a.在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
b.将v加入集合Vnew中,将<u, v>边加入集合Enew中;
4.输出:使用集合Vnew和Enew来描述所得到的最小生成树。

算法代码:

public class Net {public static final int MAX_DISTANCE = 10000;int numNodes;IntMatrix weightMatrix;public Net(int paraNumNodes) {numNodes = paraNumNodes;weightMatrix = new IntMatrix(numNodes, numNodes);for (int i = 0; i < numNodes; i++) {Arrays.fill(weightMatrix.getData()[i], MAX_DISTANCE);}}public Net(int[][] paraMatrix) {weightMatrix = new IntMatrix(paraMatrix);numNodes = weightMatrix.getRows();}public String toString() {String resultString = "This is the weight matrix of the graph.\r\n" + weightMatrix;return resultString;}public int[] shortestPath(int paraSource) {//初始化int[] tempDistanceArray = new int[numNodes];for (int i = 0; i < numNodes; i++) {tempDistanceArray[i] = weightMatrix.getValue(paraSource, i);}int[] tempParentArray = new int[numNodes];Arrays.fill(tempParentArray, paraSource);//-1表示没有父结点tempParentArray[paraSource] = -1;//已访问的节点不考虑boolean[] tempVisitedArray = new boolean[numNodes];tempVisitedArray[paraSource] = true;//主循环int tempMinDistance;int tempBestNode = -1;for (int i = 0; i < numNodes - 1; i++) {//找出最佳节点tempMinDistance = Integer.MAX_VALUE;for (int j = 0; j < numNodes; j++) {// 节点被访问if (tempVisitedArray[j]) {continue;}if (tempMinDistance > tempDistanceArray[j]) {tempMinDistance = tempDistanceArray[j];tempBestNode = j;}}tempVisitedArray[tempBestNode] = true;//准备下一轮循环for (int j = 0; j < numNodes; j++) {//节点不能到达if (tempVisitedArray[j]) {continue;}//节点不能到达if (weightMatrix.getValue(tempBestNode, j) >= MAX_DISTANCE) {continue;}if (tempDistanceArray[j] > tempDistanceArray[tempBestNode]+ weightMatrix.getValue(tempBestNode, j)) {//改变距离tempDistanceArray[j] = tempDistanceArray[tempBestNode]+ weightMatrix.getValue(tempBestNode, j);//改变父结点tempParentArray[j] = tempBestNode;}}//测试System.out.println("The distance to each node: " + Arrays.toString(tempDistanceArray));System.out.println("The parent of each node: " + Arrays.toString(tempParentArray));}//输出System.out.println("Finally");System.out.println("The distance to each node: " + Arrays.toString(tempDistanceArray));System.out.println("The parent of each node: " + Arrays.toString(tempParentArray));return tempDistanceArray;}public int prim() {//初始化,任何节点都可以是七点int tempSource = 0;int[] tempDistanceArray = new int[numNodes];for (int i = 0; i < numNodes; i++) {tempDistanceArray[i] = weightMatrix.getValue(tempSource, i);}int[] tempParentArray = new int[numNodes];Arrays.fill(tempParentArray, tempSource);//-1表示没有父结点tempParentArray[tempSource] = -1;//已访问的节点不考虑boolean[] tempVisitedArray = new boolean[numNodes];tempVisitedArray[tempSource] = true;//主循环int tempMinDistance;int tempBestNode = -1;for (int i = 0; i < numNodes - 1; i++) {//找出一个最佳节点tempMinDistance = Integer.MAX_VALUE;for (int j = 0; j < numNodes; j++) {//节点被访问if (tempVisitedArray[j]) {continue;}if (tempMinDistance > tempDistanceArray[j]) {tempMinDistance = tempDistanceArray[j];tempBestNode = j;}}tempVisitedArray[tempBestNode] = true;//准备下一轮for (int j = 0; j < numNodes; j++) {//节点被访问if (tempVisitedArray[j]) {continue;}//节点不能到达if (weightMatrix.getValue(tempBestNode, j) >= MAX_DISTANCE) {continue;}if (tempDistanceArray[j] > weightMatrix.getValue(tempBestNode, j)) {//改变距离tempDistanceArray[j] = weightMatrix.getValue(tempBestNode, j);//改变父结点tempParentArray[j] = tempBestNode;}}//测试System.out.println("The selected distance for each node: " + Arrays.toString(tempDistanceArray));System.out.println("The parent of each node: " + Arrays.toString(tempParentArray));}int resultCost = 0;for (int i = 0; i < numNodes; i++) {resultCost += tempDistanceArray[i];}//输出System.out.println("Finally");System.out.println("The parent of each node: " + Arrays.toString(tempParentArray));System.out.println("The total cost: " + resultCost);return resultCost;}public static void main(String args[]) {Net tempNet = new Net(3);System.out.println(tempNet);int[][] tempMatrix = { { 0, 9, 3, 6 }, { 5, 0, 2, 4 }, { 3, 2, 0, 1 }, { 2, 8, 7, 0 } };tempNet = new Net(tempMatrix);System.out.println(tempNet);tempNet.shortestPath(1);//需要无向图tempNet.prim();}
}

第 39 天: 关键路径


AOE网:在一个表示工程的带权有向图中,用顶点表示事件(如V0),用有向边表示活动(如<v0,v1> = a0),边上的权值表示活动的持续时间,称这样的有向图为边表示的活动的网,简称AOE网(activity on edge network)
如图,起点为V0,终点为V3.
1、只有在进入某顶点的活动都已经结束,该顶点所代表的事件才发生。例如:a1,a2活动都结束了,顶点V2所代表的事件才会发生。
2、只有在某顶点所代表的事件发生后,从该顶点出发的各活动才开始。例如:只有顶点V1所代表的事件结束之后,活动a2和a4才会开始。

事件的最早发生时间:ve[k]

根据AOE网的性质,只有进入Vk的所有活动<Vj, Vk>都结束,Vk代表的事件才能发生,而活动<Vj, Vk>的最早结束时间为ve[j]+len<Vj, Vk>。所以,计算Vk的最早发生时间的方法为:
ve[0] = 0
ve[k] = max(ve[j] + len<Vj, Vk>)

事件的最迟发生时间:vl[k]

vl[k]是指在不推迟整个工期的前提下,事件Vk允许的最迟发生时间。根据AOE网的性质,只有顶点Vk代表的事件发生,从Vk出发的活动<Vk, Vj>才能开始,而活动<Vk, Vj>的最晚开始时间为vl[j] - len<Vk, Vj>。

关键路径的计算:(以下图为例)

事件的最早发生时间:ve[k]
从源点向终点方向计算
ve[0] = 0
ve[1] = ve[0] + a0 = 0 + 4 = 4
ve[2] = max( ve[0] + a1, ve[1] + a2 ) = max(0 + 3, 4 + 2 = 6
ve[3] = max(ve[1] + a4, ve[2] + a3) = max(4 + 6, 3 + 4) = 10
事件的最迟发生时间:vl[k]
从终点向源点方向计算
vl[3] = ve[3] = 10
vl[2] = vl[3] - a3 = 10 - 4 = 6
vl[1] = min(vl[3] - a4, vl[2] - a2) = min(10-6, 6-2) = 4
vl[0] = min(vl[2] - a1, vl[1] - a0) = min(4-4, 4-2) = 0

最早开始时间和最晚开始时间相等,则说明属于关键路径。

代码:
(正向拓扑算每个节点的最早开始时间, 逆向拓扑算每个节点的最晚开始时间)

public boolean[] criticalPath() {int tempValue;//算每个节点入度int[] tempInDegrees = new int[numNodes];for (int i = 0; i < numNodes; i++) {for (int j = 0; j < numNodes; j++) {if (weightMatrix.getValue(i, j) != -1) {tempInDegrees[j]++;}} } System.out.println("In-degree of nodes: " + Arrays.toString(tempInDegrees));//拓扑排序int[] tempEarliestTimeArray = new int[numNodes];for (int i = 0; i < numNodes; i++) {//节点不能移除if (tempInDegrees[i] > 0) {continue;}System.out.println("Removing " + i);for (int j = 0; j < numNodes; j++) {if (weightMatrix.getValue(i, j) != -1) {tempValue = tempEarliestTimeArray[i] + weightMatrix.getValue(i, j);if (tempEarliestTimeArray[j] < tempValue) {tempEarliestTimeArray[j] = tempValue;}tempInDegrees[j]--;} }}System.out.println("Earlest start time: " + Arrays.toString(tempEarliestTimeArray));//计算每个节点的出度int[] tempOutDegrees = new int[numNodes];for (int i = 0; i < numNodes; i++) {for (int j = 0; j < numNodes; j++) {if (weightMatrix.getValue(i, j) != -1) {tempOutDegrees[i]++;}}}System.out.println("Out-degree of nodes: " + Arrays.toString(tempOutDegrees));//逆向拓扑排序int[] tempLatestTimeArray = new int[numNodes];for (int i = 0; i < numNodes; i++) {tempLatestTimeArray[i] = tempEarliestTimeArray[numNodes - 1];}for (int i = numNodes - 1; i >= 0; i--) {// 该节点不能移除if (tempOutDegrees[i] > 0) {continue;}System.out.println("Removing " + i);for (int j = 0; j < numNodes; j++) {if (weightMatrix.getValue(j, i) != -1) {tempValue = tempLatestTimeArray[i] - weightMatrix.getValue(j, i);if (tempLatestTimeArray[j] > tempValue) {tempLatestTimeArray[j] = tempValue;tempOutDegrees[j]--;System.out.println("The out-degree of " + j + " decreases by 1.");}}System.out.println("Latest start time: " + Arrays.toString(tempLatestTimeArray));boolean[] resultCriticalArray = new boolean[numNodes];for (int i = 0; i < numNodes; i++) {if (tempEarliestTimeArray[i] == tempLatestTimeArray[i]) {resultCriticalArray[i] = true;}}System.out.println("Critical array: " + Arrays.toString(resultCriticalArray));System.out.print("Critical nodes: ");for (int i = 0; i < numNodes; i++) {if (resultCriticalArray[i]) {System.out.print(" " + i);}}System.out.println();return resultCriticalArray;
}

第 40 天: 小结

描述这 10 天的学习体会, 不少于 10 条.

1.复习了用 this 可以调用其它的构造方法以减少冗余代码,和Exception 的抛出与捕获的机制;
2.复习了矩阵运算,发现在图的算法中用矩阵运算会变得很方便;
3.检测图的连通性可以通过矩阵运算实现;
4.复习了dfs和bfs算法,前者用栈后者用队列;
5.复习了经典回溯图的m着色问题,就是dfs;
6.图的压缩存储方式是用邻接表,也可以组成十字链表,就是将有向图的邻接表和逆邻接表结合起来;
7.迪杰斯特拉(Dijkstra)算法是单源最短路径算法,用于计算一个节点到其他节点的最短路径,与它类似的还有克鲁斯卡尔算法,是计算多源最短路径的,即每个节点到其他各节点的最短路径;
8.prim算法用于最小生成树,即要保证图的连通性的最少的边连接而成的最小权值的树;
9.计算关键路径需要用到拓扑排序,用正向拓扑计算关键路径上事件发生的最早时间,逆向拓扑计算最晚时间;
10.最早开始时间和最晚开始时间相等,则说明属于关键路径,这是一种简便方法,实际上还要看路径上的活动的完成最早和最晚的时间,如果相等则是关键路径上的活动。

Java学习日记(31-40天,图)相关推荐

  1. Java学习日记:UI篇(6)--谢尔宾斯基地毯图

    Java学习日记:UI篇(6)–谢尔宾斯基地毯图 引言:谢尔宾斯基地毯是数学家谢尔宾斯基提出的一个分形图形,谢尔宾斯基地毯和谢尔宾斯基三角形基本类似,不同之处在于谢尔宾斯基地毯采用的是正方形进行分形构 ...

  2. Java学习日记-Day01

    Java学习日记-Day01 Java语言概述 比特(byte)与字节 内存 Java基础知识图解 人机交互方式 常用的DOS命令 常用快捷键 计算机编程语言介绍 第一代语言 第二代语言 第三代语言 ...

  3. 尚学堂Java学习日记Day3

    尚学堂Java学习日记Day3 第三天老师先回顾了昨天的内容我从回顾中掌握了新的知识 如下图所示 int与double计算,输出类型为double的不同结果 会把int转成double类型的,这是隐式 ...

  4. Java学习日记1——基础认知

    Java学习日记1--基础认知 学习Java阶段,如果发现不正确的描述,还请指正! 首先附上Java相关下载链接和配置教程链接 Java相关软件工具下载地址:官方下载 Java环境配置(win10配置 ...

  5. 尚学堂Java学习日记Day1

    尚学堂学习日记Day1 #今天开始写学习博客记录自己学习java的点滴成长历程,希望能成为学弟学妹们的前车之鉴. 先大概的自我介绍下,我原本从事的是网络工程师,学习的是Cisco(思科)并拥有CCNP ...

  6. 【日记】Java学习日记(第63天)持续无聊更新

    前言 Youtube上EJ Media(up主)的视频我依次学完了HTML.CSS.Javascript.Jquery.觉得他教得挺好的(短小精悍),就继续学他教的JAVA.感觉EJ教的都是些语法什么 ...

  7. Java学习日记8:文件上传工具类的实现和服务器给客户端发送图片

    文件上传的工具类: 每次文件上传要写很多东西,把这些封装成一个工具类,以后用起来就会方便很多. 先创建一个类存储上传文件的信息: package com.upload; /*** 每上传成功一个文件的 ...

  8. 暑期学习日记31:js实现轮播图

    本次学习了使用js实现轮播图效果,逻辑为: (1)通过函数autochange()将横向排列的图片列表定时左移,来达到自动轮播的效果. (2)通过imggo(n)函数通过改变marginleft样式移 ...

  9. 黑马程序员--Java学习日记之网络编程

     ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 一.网络编程概述 1.计算机网络 计算机网络是指将地理位置不同的具有独立功能的多台计算机及 ...

最新文章

  1. 借助Oracle存储过程实现定期分割表
  2. 服务部署如何做到高可用?这份“三级跳”秘籍送给你
  3. python居中对齐代码end_Python tkinter.END属性代码示例
  4. baseline如何发布_baseline-简单的字符串基线。-Dan Gass
  5. 限制textarea的输入字数
  6. JavaScript优美的特性
  7. Flutter功能 设置Container背景色
  8. 常用PAM模块--完全笔记
  9. @PathVariable注解是什么?
  10. 了解函数式编程背后的属性:单子(Monad)
  11. 腾讯qq发起临时会话链接
  12. python 语法错误 和异常_Python基础知识:新手学Python时常见的语法错误和异常
  13. 微信公众号怎么推送消息_微信公众号发送消息
  14. 7 call和ret指令
  15. Nessus 扫描web服务
  16. UI设计教程分享:PS故障风海报制作教程
  17. 股市----别人的经验
  18. Lettuce(基于Python的BDD工具,中文编写自动化测试用例)
  19. java: Annotation processing is not supported for module cycles. Please ensure that all modules from
  20. 智能小车项目之L9110前后左右控制小车

热门文章

  1. cadworx管道设计基础到精通教程
  2. yeah邮箱功能测试
  3. 海底捞只要“面子”,不要“里子”?
  4. 微型计算机故障处理基本原则,微机故障处理的一般性原则和方法
  5. IEEE39+比利时20天然气节点+热网6节点的电气热综合能源系统,包含了CHP、EB、燃气轮机等
  6. Redis-Cluster 搭建实践
  7. tsc打印机android,使用热敏打印机Android打印条形码
  8. js 触发 change 事件
  9. influxdb查看数据库命令_02-命令行操作influx
  10. Android性能优化系列篇(三):崩溃优化+卡顿优化