1. 程式人生 > >最小生成樹-----普里姆演算法---java版

最小生成樹-----普里姆演算法---java版

最小生成樹(自己理解的,不當之處希望有人可以指出)

簡單的說一下最小生成樹:

假設一個圖,它有n個頂點,則只需n-1條邊,就可以將其組成一個連通圖,在各種組合中,所有n-1條邊的權重之和最小的連通圖,就是所謂的最小生成樹.

 

演算法思想(自己揣摩的,不當之處希望有人可以指出)

如上圖,我們以v0為起點對整個圖求其最小生成樹,過程如下:

首先既然以v0開始,那麼v0肯定就加入到了最小生成樹中,然後計算v0距離其他各個頂點的距離.不連通的以無窮大表示,則得到vo距離其他各個頂點距離如下:

這代表什麼意思呢?

其實很簡單,就是與v0相連通的點只有v1和v11,而最小生成樹要求v0必須要與圖中其他n-1箇中的某一個點進行連通,且權重值最小,因此很自然而然的我們會讓v0和v1連線起來

 

按照普里姆演算法的思想既然V0和v1這條邊已經確定了,且v0與其他各個頂點的權重值也知道了,我們這個時候可以繼續考慮一下v1的連通情況及其權重大小 ,同時由於v0和v1已經確定了,我們就先不管他們了,將其值可以都設為0,則:

 

 

上圖中得到的這個陣列表示什麼意思呢?其實很好理解,就是v0和v1兩個頂點與其它各個頂點的連通性與權重.

那這個東東有什麼用呢?這時候我們就要有一個整體的思想,為了保證連通性以及權重最小,vo和v1兩個已經確定了的點肯定要與其它的點進行連線,而上面的陣列列出了所有與v0以及v1相連通的點,只要選最小的那個,我們就找到了答案.

重複上面兩個步驟,就得到了滿足要求的最小生成樹.

package cn.nrsc.graph;

public class Graph_Prim {
	// ----------------------------圖的表示方式------------------------
	private int vertexSize;// 頂點的數量
	private int[] vertexs;// 頂點對應的陣列
	private int[][] matrix;// 鄰接矩陣
	private static final int MAX_WEIGHT = 1000;// 代表頂點之間不連通
	private boolean[] isVisited; // 頂點是否已經被訪問

	public Graph_Prim(int vertexSize) {
		this.vertexSize = vertexSize;
		this.matrix = new int[vertexSize][vertexSize];
		this.vertexs = new int[vertexSize];
		for (int i = 0; i < vertexSize; i++) {
			vertexs[i] = i;
		}

		isVisited = new boolean[vertexSize];
	}
	// ----------------------------圖的表示方式------------------------

	// 最小生成樹----普里姆演算法
	public void prim() {
		// 假設最先取出頂點0,並遍歷出它與其他所有頂點的距離----正好就是圖中鄰接矩陣的第一行
		int[] distance = matrix[0];

		int sum = 0; // 總距離

		System.out.print("查詢到點的順序:0");

		// 控制向樹中新增點的次數
		// 因為預設取出了一個點加入到了最小生成樹中,則還需要再確定另外n-1個點的加入順序
		for (int i = 1; i < vertexSize; i++) {
			// 假設初始最小值如下:
			int min = MAX_WEIGHT;
			int minId = 0;

			// 遍歷距離陣列找出該陣列中除了距離為0(說明該點已經加入到了最小生成樹中)和距離為無窮大的
			// 所有頂點中距離最小的那個----說明這個點是與已經確定的所有點可以連通,而且值最小
			for (int j = 1; j < vertexSize; j++) {
				if (distance[j] > 0 && distance[j] < MAX_WEIGHT && distance[j] < min) {
					min = distance[j];
					minId = j;
				}
			}

			// 將minId標定為已經確定的點
			distance[minId] = 0;

			System.out.print("--->" + minId);
			// 計算總距離
			sum += min;

			// 遍歷minId點的所有鄰接點,找到已確定點到其他未知點之間更小的距離
			// 0肯定不用再遍歷了,因為第一個確定的點就是它,所以從1開始
			for (int k = 1; k < vertexSize; k++) {
				if (distance[k] > 0 && distance[k] > matrix[minId][k]) {
					distance[k] = matrix[minId][k];
				}
			}
		}
		System.out.println();
		System.out.println("最小生成樹的總距離為:" + sum);

	}
	// 最小生成樹----普里姆演算法

	public static void main(String[] args) {
		Graph_Prim graph = new Graph_Prim(9);
		int[] v0 = { 0, 10, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 11, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT };
		int[] v1 = { 10, 0, 18, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 16, MAX_WEIGHT, 12 };
		int[] v2 = { MAX_WEIGHT, MAX_WEIGHT, 0, 22, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 8 };
		int[] v3 = { MAX_WEIGHT, MAX_WEIGHT, 22, 0, 20, MAX_WEIGHT, 24, 16, 21 };
		int[] v4 = { MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 20, 0, 26, MAX_WEIGHT, 7, MAX_WEIGHT };
		int[] v5 = { 11, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 26, 0, 17, MAX_WEIGHT, MAX_WEIGHT };
		int[] v6 = { MAX_WEIGHT, 16, MAX_WEIGHT, 24, MAX_WEIGHT, 17, 0, 19, MAX_WEIGHT };
		int[] v7 = { MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 16, 7, MAX_WEIGHT, 19, 0, MAX_WEIGHT };
		int[] v8 = { MAX_WEIGHT, 12, 8, 21, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 0 };

		graph.matrix[0] = v0;
		graph.matrix[1] = v1;
		graph.matrix[2] = v2;
		graph.matrix[3] = v3;
		graph.matrix[4] = v4;
		graph.matrix[5] = v5;
		graph.matrix[6] = v6;
		graph.matrix[7] = v7;
		graph.matrix[8] = v8;
		
		//test
		graph.prim();

	}
}