06-圖

圖的表示方式:鄰接矩陣、鄰接鏈表

1. 鄰接矩陣表示圖

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

// 圖的鄰接矩陣存儲(chǔ)結(jié)構(gòu)
public class Graph {
    int maxVertexNum; // 最大頂點(diǎn)數(shù)
    List<String> vertex; // 頂點(diǎn)表
    int[][] edge; // 鄰接矩陣结蟋,邊表
    int edgeNum; // 圖中當(dāng)前的邊數(shù)
    boolean[] visited; // 頂點(diǎn)是否被訪問(wèn)

    public Graph(int maxVertexNum) {
        this.maxVertexNum = maxVertexNum;
        vertex = new ArrayList<>(maxVertexNum);
        edge = new int[maxVertexNum][maxVertexNum];
        visited = new boolean[maxVertexNum];
    }

    // 顯示鄰接矩陣
    public void display() {
        for (int i = 0; i < edge.length; i++) {
            System.out.println(Arrays.toString(edge[i]));
        }
    }

    // 在圖中插入一個(gè)頂點(diǎn)
    public void insertVertex(String vertex) {
        this.vertex.add(vertex);
    }

    // 向圖中添加一條無(wú)向邊<vs, ve>蜒犯,其權(quán)值為weight
    public void addEdge(int vs, int ve, int weight) {
        edge[vs][ve] = weight;
        edge[ve][vs] = weight;
        edgeNum++;
    }

    // 獲取邊<vs, ve>的權(quán)值
    public int getEdgeValue(int vs, int ve) {
        return edge[vs][ve];
    }

    // 獲取頂點(diǎn)vertex的第一個(gè)鄰接點(diǎn)*
    public int firstNeighbor(int vertex) {
        for (int c = 0; c < this.vertex.size(); c++) {
            if (edge[vertex][c] > 0)
                return c;
        }
        return -1;
    }

    // 獲取vertex的除了exclude頂點(diǎn)的下一個(gè)鄰接點(diǎn)*
    public int nextNeighbor(int vertex, int exclude) {
        for (int c = exclude + 1; c < this.vertex.size(); c++) {
            if (edge[vertex][c] > 0)
                return c;
        }
        return -1;
    }

    // 對(duì)圖進(jìn)行深度優(yōu)先遍歷
    public void dfsTraverse() {
        int vertexNum = vertex.size();
        // 初始化visited
        for (int v = 0; v < vertexNum; v++)
            visited[v] = false;
        // 從0開(kāi)始逐個(gè)訪問(wèn)
        for (int v = 0; v < vertexNum; v++)
            if (!visited[v])
                dfs(v);
    }

    // Depth First Search,深度優(yōu)先搜索,遞歸
    private void dfs(int v) {
        System.out.print(vertex.get(v) + " "); // 訪問(wèn)頂點(diǎn)v
        visited[v] = true; // 標(biāo)記為已被訪問(wèn)
        // adjacent為v的尚未被訪問(wèn)的鄰接頂點(diǎn)
        for (int adjacent = firstNeighbor(v); adjacent >= 0; adjacent = nextNeighbor(v, adjacent)) {
            // v的所有鄰接結(jié)點(diǎn)是從左到右按順序訪問(wèn)
            if (!visited[adjacent])
                dfs(adjacent);
        }
    }

    // 借助棧渠鸽,非遞歸颈抚,從頂點(diǎn)v開(kāi)始深度優(yōu)先*
    public void dfsTraverse(int v) {
        LinkedList<Integer> stack = new LinkedList<>();
        // 初始化visited
        for (int i = 0; i < vertex.size(); i++)
            visited[i] = false;
        // 將v入棧踩衩,入棧一個(gè)就將其置為已被訪問(wèn)
        stack.push(v);
        visited[v] = true;
        while (!stack.isEmpty()) {
            // 出棧一個(gè)頂點(diǎn)并訪問(wèn)
            v = stack.pop();
            System.out.print(vertex.get(v) + " ");
            // 將v的所有鄰接結(jié)點(diǎn)adjacent入棧
            for (int adjacent = firstNeighbor(v); adjacent >= 0; adjacent = nextNeighbor(v, adjacent))
                // 由于是棧,因此v的所有鄰接結(jié)點(diǎn)是從右到左逆序訪問(wèn)
                if (!visited[adjacent]) { // 未進(jìn)過(guò)棧的頂點(diǎn)入棧
                    stack.push(adjacent);
                    visited[adjacent] = true;
                }
        }
    }

    // 對(duì)圖進(jìn)行廣度優(yōu)先遍歷
    public void bfsTraverse() {
        // 初始化visited
        for (int i = 0; i < vertex.size(); i++)
            visited[i] = false;
        // 從0開(kāi)始逐個(gè)訪問(wèn)
        for (int i = 0; i < vertex.size(); i++)
            if (!visited[i])
                bfs(i);
    }

    // Breadth First Search,廣度優(yōu)先搜索驱富,借助隊(duì)列锚赤,非遞歸*
    private void bfs(int v) {
        LinkedList<Integer> queue = new LinkedList<>();
        // 訪問(wèn)v,并將其入隊(duì)
        System.out.print(vertex.get(v) + " ");
        visited[v] = true;
        queue.addLast(v);
        while (!queue.isEmpty()) {
            // 頂點(diǎn)v出隊(duì)
            v = queue.removeFirst();
            // 訪問(wèn)v的所有鄰接點(diǎn)
            for (int adjacent = firstNeighbor(v); adjacent >= 0; adjacent = nextNeighbor(v, adjacent))
                if (!visited[adjacent]) {
                    // 訪問(wèn)adjacent褐鸥,并將其入隊(duì)
                    System.out.print(vertex.get(adjacent) + " ");
                    visited[adjacent] = true;
                    queue.addLast(adjacent);
                }
        }
    }
}

// 測(cè)試
class GraphClient {
    public static void main(String[] args) {
        String[] vertex = {"1", "2", "3", "4", "5", "6", "7", "8"};
        Graph graph = new Graph(vertex.length);
        for (String s : vertex)
            graph.insertVertex(s);
        graph.addEdge(0, 1, 1); // 1-2
        graph.addEdge(0, 2, 1); // 1-3
        graph.addEdge(1, 3, 1); // 2-4
        graph.addEdge(1, 4, 1); // 2-5
        graph.addEdge(2, 5, 1); // 3-6
        graph.addEdge(2, 6, 1); // 3-7
        graph.addEdge(3, 7, 1); // 4-8
        graph.addEdge(4, 7, 1); // 5-8
        graph.addEdge(5, 6, 1); // 6-7
        graph.display();
        System.out.println("遞歸深度優(yōu)先:");
        // 1 2 4 8 5 3 6 7
        graph.dfsTraverse();
        System.out.println("\n非遞歸深度優(yōu)先:");
        // 1 3 7 6 2 5 8 4
        graph.dfsTraverse(0);
        System.out.println("\n非遞歸廣度優(yōu)先:");
        // 1 2 3 4 5 6 7 8
        graph.bfsTraverse();
    }
}

2. 最小生成樹(shù)

最小生成樹(shù)可以用Prim(普里姆)算法或Kruskal(克魯斯卡爾)算法求出线脚。

Prim算法簡(jiǎn)述:

  1. 輸入:一個(gè)加權(quán)連通圖,其中頂點(diǎn)集合為V叫榕,邊集合為E
  2. 初始化:V_{new}=\{ x \}酒贬,其中x為集合V中的任一節(jié)點(diǎn),E_{new}=\{ \}翠霍,為空
  3. 重復(fù)下列操作锭吨,直到V_{new}=V
    1. 在集合E中選取權(quán)值最小的邊<u,v>,其中u為集合V_{new}中的元素寒匙,而v不在V_{new}集合當(dāng)中零如,并且v \in V(如果存在有多條滿足前述條件即具有相同權(quán)值的邊,則可任意選取其中之一)
    2. 將v加入集合V_{new}中锄弱,將<u,v>邊加入集合E_{new}
  4. 輸出:使用集合V_{new}E_{new}來(lái)描述所得到的最小生成樹(shù)

Kruskal算法簡(jiǎn)述:

  1. 構(gòu)造一個(gè)只含n個(gè)頂點(diǎn)考蕾,而邊集為空的子圖,若將該子圖中各個(gè)頂點(diǎn)看成是各棵樹(shù)上的根結(jié)點(diǎn)会宪,則它是一個(gè)含有n棵樹(shù)的一個(gè)森林肖卧。
  2. 從邊集E中選取一條權(quán)值最小的邊,若該條邊的兩個(gè)頂點(diǎn)分屬不同的樹(shù)掸鹅,則將其加入子圖塞帐;反之,若該條邊的兩個(gè)頂點(diǎn)已落在同一棵樹(shù)上巍沙,則不可取葵姥,而應(yīng)該取下一條權(quán)值最小的邊再試之。直至森林中只有一棵樹(shù)句携,也即子圖中含有n-1條邊為止榔幸。
import java.util.ArrayList;
import java.util.List;

class Edge {
    String start;
    String end;
    int weight;

    public Edge(String start, String end, int weight) {
        this.start = start;
        this.end = end;
        this.weight = weight;
    }
}

public class MinimumSpanningTree {
    // prim求解最小生成樹(shù),v表示從第v個(gè)頂點(diǎn)開(kāi)始生成
    public static void prim(Graph graph, int v) {
        // visited標(biāo)記結(jié)點(diǎn)是否被訪問(wèn)
        boolean[] visited = new boolean[graph.maxVertexNum];
        // 初始化visited
        for (int i = 0; i < visited.length; i++)
            visited[i] = false;
        // 頂點(diǎn)v已被訪問(wèn)
        visited[v] = true;
        // vs和ve記錄兩個(gè)頂點(diǎn)的下標(biāo)
        int vs = -1;
        int ve = -1;
        int minWeight = Integer.MAX_VALUE;
        for (int k = 1; k < graph.maxVertexNum; k++) {
            // 確定每一次生成的子圖和哪個(gè)結(jié)點(diǎn)的距離最近
            for (int i = 0; i < graph.maxVertexNum; i++) { // 遍歷已經(jīng)訪問(wèn)過(guò)的結(jié)點(diǎn)
                for (int j = 0; j < graph.maxVertexNum; j++) { // 遍歷所有沒(méi)有訪問(wèn)過(guò)的結(jié)點(diǎn)
                    // 如果是一個(gè)訪問(wèn)過(guò)的結(jié)點(diǎn)和一個(gè)沒(méi)有訪問(wèn)過(guò)的結(jié)點(diǎn)矮嫉,并且當(dāng)前邊的權(quán)值小于最小權(quán)值
                    if (visited[i] == true && visited[j] == false && graph.edge[i][j] < minWeight) {
                        minWeight = graph.edge[i][j];
                        vs = i;
                        ve = j;
                    }
                }
            }
            System.out.println(graph.vertex.get(vs) + "->" + graph.vertex.get(ve) + ": " + minWeight);
            visited[ve] = true;
            minWeight = Integer.MAX_VALUE;
        }
    }

    // kruskal求解最小生成樹(shù)
    public static void kruskal(Graph graph, List<Edge> edges) {
        // 保存已有最小生成樹(shù)中削咆,每個(gè)頂點(diǎn)所在樹(shù)的根的索引
        int[] ends = new int[edges.size()];
        // 對(duì)邊進(jìn)行排序,按照權(quán)值從小到大
        edges.sort(((o1, o2) -> o1.weight - o2.weight));
        // 遍歷邊集合蠢笋,將邊添加到最小生成樹(shù)中
        // 判斷準(zhǔn)備加入的邊是否形成回路拨齐,即是同一棵樹(shù)的兩個(gè)頂點(diǎn)
        for (int i = 0; i < edges.size(); i++) {
            // 獲取第i條邊的起點(diǎn)索引
            int start = graph.vertex.indexOf(edges.get(i).start);
            // 獲取第i條邊的終點(diǎn)索引
            int end = graph.vertex.indexOf(edges.get(i).end);
            // 獲取起點(diǎn)所在樹(shù)的根索引
            int startRoot = getRoot(ends, start);
            // 獲取終點(diǎn)所在樹(shù)的根索引
            int endRoot = getRoot(ends, end);
            if (startRoot != endRoot) { // 不在同一棵樹(shù)
                // 設(shè)置startRoot這棵樹(shù)在已有最小生成樹(shù)中的終點(diǎn)
                ends[startRoot] = endRoot;
                // 輸出這一條邊
                System.out.println(edges.get(i).start + "--" + edges.get(i).end + ": " + edges.get(i).weight);
            }
        }
    }

    // (kruskal的難點(diǎn))返回頂點(diǎn)i所在樹(shù)的根的索引,ends數(shù)組記錄各個(gè)頂點(diǎn)所在樹(shù)的根的索引
    private static int getRoot(int[] ends, int i) {
        while (ends[i] != 0)
            i = ends[i];
        return i;
    }

    // 測(cè)試
    public static void main(String[] args) {
        String[] vertex = {"V1", "V2", "V3", "V4", "V5", "V6"};
        // 將頂點(diǎn)加入到集合
        List<String> list = new ArrayList<>();
        for (String v : vertex)
            list.add(v);
        // max表示不連通
        int max = Integer.MAX_VALUE;
        // 初始化鄰接矩陣
        int[][] edge = new int[][]{
                {max, 6, 1, 5, max, max},
                {6, max, 5, max, 3, max},
                {1, 5, max, 5, 6, 4},
                {5, max, 5, max, max, 2},
                {max, 3, 6, max, max, 6},
                {max, max, 4, 2, 6, max}
        };
        // 將邊加入到集合
        List<Edge> edges = new ArrayList<>();
        for (int r = 0; r < edge.length; r++)
            for (int c = r + 1; c < edge[r].length; c++)
                if (edge[r][c] != max)
                    edges.add(new Edge(vertex[r], vertex[c], edge[r][c]));
        // 創(chuàng)建一個(gè)圖挺尿,圖是自己定義的
        Graph graph = new Graph(vertex.length);
        graph.vertex = list;
        graph.edge = edge;
        graph.edgeNum = edges.size();
        prim(graph, 0);
        System.out.println("---------");
        kruskal(graph, edges);
    }
}

3. 最短路徑

最短路徑可以用Dijkstra(迪杰斯特拉)算法或Floyd(弗洛伊德)算法求出奏黑。

  1. Dijkstra算法可以求出指定頂點(diǎn)到其他各個(gè)頂點(diǎn)的最短路徑
  2. Floyd算法可以求出每一個(gè)頂點(diǎn)到其他各個(gè)頂點(diǎn)的最短路徑

Dijkstra算法過(guò)程:Dijkstra算法不適用于含有負(fù)權(quán)邊的圖

  1. 初始化:集合S初始為{0},dist[]的初始值dist[i]=arcs[0][i],i=1,2,...,n-1编矾。
  2. 從頂點(diǎn)集合V-S中選出v_j熟史,滿足dist[j]=Min \{ dist[i] | v_{i} \in V-S \}v_j就是當(dāng)前求得的一條從v_0出發(fā)的最短路徑的終點(diǎn)窄俏,令S=S \cup \{j\}蹂匹。
  3. 修改從v_0出發(fā)到集合V-S上任一頂點(diǎn)v_k可達(dá)的最短路徑長(zhǎng)度:若dist[j]+arcs[j][k]<dist[k],則令dist[k]=dist[j]+arcs[j][k]凹蜈。
  4. 重復(fù)2~3操作共n-1次限寞,直到所有的頂點(diǎn)都包含在S中。
  • dist[]:記錄從源點(diǎn)v_0到其他各頂點(diǎn)當(dāng)前的最短路徑長(zhǎng)度仰坦,dist[i]的初值為arcs[v_0][i]履植。
  • path[]:path[i]表示從源點(diǎn)到頂點(diǎn)i之間的最短路徑的前驅(qū)結(jié)點(diǎn),在算法結(jié)束時(shí)悄晃,可根據(jù)其值追溯得到源點(diǎn)v_0到頂點(diǎn)v_i的最短路徑玫霎。

Floyd算法過(guò)程:Floyd算法又稱為插點(diǎn)法,利用了動(dòng)態(tài)規(guī)劃的思想

  1. 從任意一條單邊路徑開(kāi)始妈橄。所有兩點(diǎn)之間的距離是邊的權(quán)庶近,如果兩點(diǎn)之間沒(méi)有邊相連,則權(quán)為無(wú)窮大眷蚓。
  2. 對(duì)于每一對(duì)頂點(diǎn)u和v鼻种,看看是否存在一個(gè)頂點(diǎn)w使得從u到w再到v比已知的路徑更短,如果存在則更新它沙热。
  • 把圖用鄰接矩陣G表示出來(lái)叉钥,如果從v_iv_j有路可達(dá),則G[i][j]=d篙贸,d表示該路的長(zhǎng)度沼侣;否則G[i][j]=+\infty。定義一個(gè)矩陣D用來(lái)記錄所插入點(diǎn)的信息歉秫,D[i][j]表示從v_iv_j需要經(jīng)過(guò)的點(diǎn)蛾洛,初始化D[i][j]=j。把各個(gè)頂點(diǎn)插入圖中雁芙,比較插點(diǎn)后的距離與原來(lái)的距離轧膘,G[i][j]=min(G[i][j],G[i][k]+G[k][j]),如果G[i][j]的值變小兔甘,則D[i][j]=k谎碍。在G中包含有兩點(diǎn)之間最短道路的信息,而在D中則包含了最短通路徑的信息洞焙。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

// Dijkstra算法的輔助數(shù)組類
class AuxiliaryArray {
    // 記錄各個(gè)頂點(diǎn)是否訪問(wèn)過(guò):1訪問(wèn)過(guò)蟆淀,0未訪問(wèn)
    int[] visited;
    // 記錄從源點(diǎn)到其他各頂點(diǎn)當(dāng)前的最短路徑長(zhǎng)度
    int[] dist;
    // path[i]表示從源點(diǎn)到頂點(diǎn)i之間的最短路徑的前驅(qū)結(jié)點(diǎn)
    int[] path;
    // 頂點(diǎn)數(shù)
    int vertexNum;
    // 源點(diǎn)的索引
    int source;

    public AuxiliaryArray(int vertexNum, int source) {
        this.vertexNum = vertexNum;
        this.source = source;
        visited = new int[vertexNum];
        dist = new int[vertexNum];
        path = new int[vertexNum];
        Arrays.fill(dist, Integer.MAX_VALUE / 2); // 初始化dist數(shù)組
        visited[source] = 1; // 標(biāo)記源點(diǎn)已被訪問(wèn)
        dist[source] = 0; // 設(shè)置源點(diǎn)到源點(diǎn)的距離為0
    }

    // 判斷頂點(diǎn)v是否被訪問(wèn)過(guò)
    public boolean isVisited(int v) {
        return visited[v] == 1;
    }

    // 返回從源點(diǎn)到頂點(diǎn)v當(dāng)前的最短路徑長(zhǎng)度
    public int getDistance(int v) {
        return dist[v];
    }

    // 更新源點(diǎn)到頂點(diǎn)v的距離為distance
    public void updateDist(int v, int distance) {
        dist[v] = distance;
    }

    // 更新頂點(diǎn)v的前驅(qū)結(jié)點(diǎn)為頂點(diǎn)prev
    public void updatePath(int v, int prev) {
        path[v] = prev;
    }

    // 選出vj拯啦,dist[j]為剩余結(jié)點(diǎn)i中dist[i]最小的
    public int next() {
        int minValue = Integer.MAX_VALUE / 2;
        int minIndex = 0;
        for (int i = 0; i < visited.length; i++) {
            if (visited[i] == 0 && dist[i] < minValue) {
                minValue = dist[i];
                minIndex = i;
            }
        }
        // 更新minIndex頂點(diǎn)被訪問(wèn)過(guò)
        visited[minIndex] = 1;
        return minIndex;
    }

    // 便于展示
    public void display(List<String> vertex) {
        System.out.println("visited: ");
        for (int i = 0; i < visited.length; i++)
            System.out.print(visited[i] + " ");
        System.out.println("\npath: ");
        for (int i = 0; i < path.length; i++)
            System.out.print(path[i] + " ");
        System.out.println("\ndist: ");
        for (int i = 0; i < dist.length; i++)
            System.out.print(dist[i] + " ");
        System.out.println("\n源點(diǎn)" + vertex.get(source) + "到各頂點(diǎn)的最短路徑:");
        for (int i = 0; i < dist.length; i++) {
            if (dist[i] != Integer.MAX_VALUE / 2)
                System.out.print(vertex.get(source) + "-" + dist[i] + "->" + vertex.get(i) + "\t");
            else
                System.out.print("MAX ");
        }
    }
}

public class ShortestPath {
    // dijkstra更新輔助數(shù)組Dist和Path
    private static void updateDistAndPath(Graph graph, AuxiliaryArray auxiliary, int j) {
        // 遍歷鄰接矩陣的第j行
        for (int k = 0; k < graph.edge[j].length; k++) {
            // distance表示源點(diǎn)到頂點(diǎn)v的距離+源點(diǎn)到頂點(diǎn)j的距離
            int distance = auxiliary.getDistance(j) + graph.edge[j][k];
            // 如果頂點(diǎn)j沒(méi)有被訪問(wèn)過(guò),并且distance小于源點(diǎn)到頂點(diǎn)j的距離熔任,就更新
            if (!auxiliary.isVisited(k) && distance < auxiliary.getDistance(k)) {
                // 更新頂點(diǎn)j的前驅(qū)結(jié)點(diǎn)為頂點(diǎn)v
                auxiliary.updatePath(k, j);
                // 更新源點(diǎn)到頂點(diǎn)j的距離為distance
                auxiliary.updateDist(k, distance);
            }
        }
    }

    // Dijkstra算法求最短路徑
    public static void dijkstra(Graph graph, AuxiliaryArray auxiliary, int source) {
        updateDistAndPath(graph, auxiliary, source);
        for (int j = 1; j < graph.vertex.size(); j++) {
            // 獲取下一個(gè)訪問(wèn)頂點(diǎn)next
            int next = auxiliary.next();
            // 設(shè)置到next頂點(diǎn)的最短路徑和前驅(qū)
            updateDistAndPath(graph, auxiliary, next);
        }
    }

    // Floyd算法求最短路徑
    public static void floyd(Graph graph, int[][] dist, int[][] path) {
        // 初始化dist為鄰接矩陣
        for (int r = 0; r < graph.maxVertexNum; r++)
            for (int c = 0; c < graph.maxVertexNum; c++)
                dist[r][c] = graph.edge[r][c];
        // 初始化path
        for (int i = 0; i < graph.maxVertexNum; i++)
            // 初始時(shí)褒链,各個(gè)頂點(diǎn)到源點(diǎn)i的前驅(qū)默認(rèn)為i
            Arrays.fill(path[i], i);
        // Floyd求最短路徑過(guò)程
        for (int k = 0; k < dist.length; k++) { // 中間頂點(diǎn)k
            for (int i = 0; i < dist.length; i++) { // 從頂點(diǎn)i出發(fā)
                for (int j = 0; j < dist.length; j++) { // 到達(dá)頂點(diǎn)j
                    // distance為路徑i-->k-->j的距離
                    int distance = dist[i][k] + dist[k][j];
                    // 如果i-->k-->j的距離小于i-->j的距離
                    if (distance < dist[i][j]) {
                        // 更新最短路徑
                        dist[i][j] = distance;
                        // 更新前驅(qū)
                        path[i][j] = path[k][j];
                    }
                }
            }
        }
    }

    // 測(cè)試
    public static void main(String[] args) {
        String[] vertex = {"A", "B", "C", "D", "E", "F", "G"};
        // 將頂點(diǎn)加入到集合
        List<String> list = new ArrayList<>();
        for (String v : vertex)
            list.add(v);
        // max表示不連通
        int max = Integer.MAX_VALUE / 2;
        // 初始化鄰接矩陣
        int[][] edge = new int[][]{
                {0, 5, 7, max, max, max, 2},
                {5, 0, max, 9, max, max, 3},
                {7, max, 0, max, 8, max, max},
                {max, 9, max, 0, max, 4, max},
                {max, max, 8, max, 0, 5, 4},
                {max, max, max, 4, 5, 0, 6},
                {2, 3, max, max, 4, 6, 0}
        };
        // 創(chuàng)建一個(gè)圖,圖是自己定義的
        Graph graph = new Graph(vertex.length);
        graph.vertex = list;
        graph.edge = edge;

        System.out.println("-----Dijkstra-----");
        AuxiliaryArray auxiliary = new AuxiliaryArray(graph.maxVertexNum, 2);
        dijkstra(graph, auxiliary, auxiliary.source);
        auxiliary.display(graph.vertex);

        System.out.println("\n-----Floyd-----");
        int[][] dist = new int[graph.maxVertexNum][graph.maxVertexNum];
        int[][] path = new int[graph.maxVertexNum][graph.maxVertexNum];
        floyd(graph, dist, path);
        // 遍歷dist和path
        for (int r = 0; r < dist.length; r++) {
            System.out.print("各個(gè)頂點(diǎn)到源點(diǎn)" + graph.vertex.get(r) + "的前驅(qū):");
            for (int c = 0; c < dist.length; c++)
                System.out.print(vertex[path[r][c]] + " ");
            System.out.println();
            for (int c = 0; c < dist.length; c++)
                System.out.print(vertex[r] + "-" + dist[r][c] + "->" + vertex[c] + "\t");
            System.out.println();
        }
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末疑苔,一起剝皮案震驚了整個(gè)濱河市甫匹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌惦费,老刑警劉巖兵迅,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異薪贫,居然都是意外死亡恍箭,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)瞧省,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)季惯,“玉大人,你說(shuō)我怎么就攤上這事臀突∶阕ィ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵候学,是天一觀的道長(zhǎng)藕筋。 經(jīng)常有香客問(wèn)我,道長(zhǎng)梳码,這世上最難降的妖魔是什么隐圾? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮掰茶,結(jié)果婚禮上暇藏,老公的妹妹穿的比我還像新娘。我一直安慰自己濒蒋,他們只是感情好盐碱,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著沪伙,像睡著了一般瓮顽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上围橡,一...
    開(kāi)封第一講書(shū)人閱讀 52,441評(píng)論 1 310
  • 那天暖混,我揣著相機(jī)與錄音,去河邊找鬼翁授。 笑死拣播,一個(gè)胖子當(dāng)著我的面吹牛晾咪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播贮配,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼谍倦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了牧嫉?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤减途,失蹤者是張志新(化名)和其女友劉穎酣藻,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鳍置,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡辽剧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了税产。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片怕轿。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖辟拷,靈堂內(nèi)的尸體忽然破棺而出撞羽,到底是詐尸還是另有隱情,我是刑警寧澤衫冻,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布诀紊,位于F島的核電站,受9級(jí)特大地震影響隅俘,放射性物質(zhì)發(fā)生泄漏邻奠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一为居、第九天 我趴在偏房一處隱蔽的房頂上張望碌宴。 院中可真熱鬧,春花似錦蒙畴、人聲如沸贰镣。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)八孝。三九已至,卻和暖如春鸠项,著一層夾襖步出監(jiān)牢的瞬間干跛,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工祟绊, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留楼入,地道東北人哥捕。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像嘉熊,于是被迫代替她去往敵國(guó)和親遥赚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容