1. 程式人生 > 其它 >月【貪心 人類智慧】

月【貪心 人類智慧】

基本介紹

普里姆演算法(Prim演算法),圖論中的一種演算法,可在加權連通圖裡搜尋最小生成樹。意即由此演算法搜尋到的邊子集所構成的樹中,不但包括了連通圖裡的所有頂點(英語:Vertex (graph theory)),且其所有邊的權值之和亦為最小。該演算法於1930年由捷克數學家沃伊捷赫·亞爾尼克(英語:Vojtěch Jarník)發現;並在1957年由美國電腦科學家羅伯特·普里姆(英語:Robert C. Prim)獨立發現;1959年,艾茲格·迪科斯徹再次發現了該演算法。因此,在某些場合,普里姆演算法又被稱為DJP演算法、亞爾尼克演算法或普里姆-亞爾尼克演算法。

案例


1)有勝利鄉有7個村莊(A, B, C, D, E, F, G) ,現在需要修路把7個村莊連通
2)各個村莊的距離用邊線表示(權) ,比如 A – B 距離 5公里
3)問:如何修路保證各個村莊都能連通,並且總的修建公路總里程最短?

最小生成樹

這個問題本質上就是最小生成樹問題,最小生成樹:一個有 n 個結點的連通圖的生成樹是原圖的極小連通子圖,且包含原圖中的所有 n 個結點,並且有保持圖連通的最少的邊。最小生成樹可以用kruskal(克魯斯卡爾)演算法或prim(普里姆)演算法求出。

思路

程式碼

import java.util.Arrays;

public class PrimAlgorithm {
  public static void main(String[] args) {
    char[] data = {'A','B','C','D','E','F','G'};
    int [][]weight=new int[][]{  //10000表示不通
            {10000,5,7,10000,10000,10000,2},
            {5,10000,10000,9,10000,10000,3},
            {7,10000,10000,10000,8,10000,10000},
            {10000,9,10000,10000,10000,4,10000},
            {10000,10000,8,10000,10000,5,4},
            {10000,10000,10000,4,5,10000,6},
            {2,3,10000,10000,4,6,10000},};
    int vertex = data.length;
    MGraph graph = new MGraph(vertex);
    MinTree minTree = new MinTree();
    minTree.createGraph(graph,vertex,data,weight);
    minTree.showGraph(graph);
    minTree.prim(graph,0);
  }
}

class MGraph {
  int vertex; //頂點個數
  char[] data;  //存放頂點
  int[][] weight; //鄰接矩陣

  public MGraph(int vertex) {
    this.vertex = vertex;
    weight = new int[vertex][vertex];
    data = new char[vertex];
  }
}

class MinTree {

  /**
   * 建立圖的鄰接矩陣
   * @param graph 圖物件
   * @param vertex 圖頂點個數
   * @param data 圖的頂點的值
   * @param weight 圖對應的鄰接矩陣
   */
  public void createGraph(MGraph graph,int vertex,char[] data,int[][] weight) {
    int i, j;
    for(i = 0; i < vertex; i++) {
      graph.data[i] = data[i];
      for(j = 0; j < vertex; j++) {
        graph.weight[i][j] = weight[i][j];
      }
    }
  }

  /**
   * 顯示圖的鄰接矩陣
   * @param graph 圖物件
   */
  public void showGraph(MGraph graph) {
    for (int[] link : graph.weight) {
      System.out.println("link = " + Arrays.toString(link));
    }
  }

  /**
   * 普利姆演算法
   * @param graph 圖物件
   * @param v 表示從哪個頂點開始
   */
  public void prim(MGraph graph,int v) {
    int[] visited = new int[graph.vertex];  //0表示未使用,1表示已使用
    visited[v] = 1;
    int index1 = 0;
    int index2 = 0;
    int minWeight = Integer.MAX_VALUE;  //假設最小權值
    for (int i = 1; i < graph.vertex; i++) {
      for (int j = 0; j < graph.vertex; j++) {
        for (int k = 0; k < graph.vertex; k++) {
          if (visited[j] == 1 && visited[k] == 0 && graph.weight[j][k] < minWeight) {
            minWeight = graph.weight[j][k];
            index1 = j;
            index2 = k;
          }
        }
      }
      System.out.println("邊為=>" + graph.data[index1] + ">" + graph.data[index2] + ",權值是" + minWeight);
      visited[index2] = 1;
      minWeight = Integer.MAX_VALUE;
    }
  }

}