利用克鲁斯卡尔算法求最小生成树
思路:最小生成樹即為無向連通圖G的一個子圖如果是一顆包含G的所有頂點且權最小的樹則稱為最小生成樹??唆斔箍査惴ǖ幕舅枷胧且赃厼橹鲗У匚?#xff0c;始終選擇當前可用的(所選的邊不能構成回路)最小權值邊。所以第一步是將所有邊按照權值從小到大的順序排序,接下來從小到大依次考察每一條邊。具體實現過程如下:
<1>設一個有n個頂點的連通網絡為G(V,E),最初先構造一個只有n個頂點,沒有邊的非連通圖T={V,空},圖中每個頂點自成一格連通分量。
<2>在E中選擇一條具有最小權植的邊時,若該邊的兩個頂點落在不同的連通分量上,則將此邊加入到T中;否則,即這條邊的兩個頂點落到同一連通分量上,則將此邊舍去(此后永不選用這條邊),重新選擇一條權植最小的邊。
<3>如此重復下去,直到所有頂點在同一連通分量上為止。
在上面的算法思路中,最為復雜的部分是連通分量的查詢和合并,并查集這個數據結構可以方便快速的解決這個問題。基本的處理思想是:初始時把每個對象看作是一個單元素集合;然后依次按順序讀入聯通邊,將連通邊中的兩個元素合并。在此過程中將重復使用一個搜索(Find)運算,確定一個集合在那個集合中。當讀入一個連通邊(u,v)時,先判斷u和v是否在同一個集合中,如果是則不用合并;如果不是,則用一個合并運算把u、v所在集合合并,使得這兩個集合中的任意兩個元素都連通。因此并查集在處理時,主要用到搜索和合并兩個運算。為了方便并查集的描述與實現,通常把先后加入到一個集合中的元素表示成一個樹結構,并用根結點的序號(在這里根節點的序號就是數組的下標值)來表示這個集合。因此定義一個parent[n]的數組,parent[i]中存放的就是結點i+1所在的樹中結點i+1的父親節點的序號。
#include<stdio.h> #include<stdlib.h> #define MAXVEX 20 #define INF 32767 typedef struct {int arcs[MAXVEX][MAXVEX];char vex[MAXVEX];int vexnum;int arcnum; }AdjMatrix; //圖 typedef struct {int start;int end;int weight;int isUsed; } Brim; //邊 int LocateVex(AdjMatrix* G, char v); void Create(AdjMatrix *G); int Find(int *parent, int f); void Kruskal(AdjMatrix *G) int main() {AdjMatrix* G = (AdjMatrix*)malloc(sizeof(AdjMatrix));Create(G);Kruskal(G);return 0; }int Find(int *parent, int f) {//從下標f開始尋找parent數組中元素為0的下標int x;for(x = f;parent[x] > 0; x=parent[x]);return x; } void Create(AdjMatrix *G) {int i, j, k;char vex1, vex2;int weight;scanf("%d%d", &G->vexnum, &G->arcnum);getchar();for (i = 0; i < G->vexnum; i++){for (j = 0; j < G->vexnum; j++){G->arcs[i][j] = INF;}}for (i = 0; i < G->vexnum; i++){scanf("%c", &G->vex[i]); //輸入各個頂點 }getchar();for (i = 0; i < G->arcnum; i++){scanf("(%c,%c,%d)", &vex1, &vex2, &weight); //輸入邊的信息 j = LocateVex(G, vex1);k = LocateVex(G, vex2);G->arcs[j][k] = weight;G->arcs[k][j] = weight;} }void Kruskal(AdjMatrix *G) { Brim brim[MAXVEX];int i, j;int k = 0;int n, m;for (i = 0; i < G->vexnum- 1; i++) { //生成樹最多只有n-1條邊 for (j = i + 1; j < G->vexnum; j++) {if (G->arcs[i][j] != INF) {brim[k].start = i;brim[k].end = j;brim[k].weight = G->arcs[i][j];brim[k].isUsed = 0;k++;}}}for (i = 0; i < k - 1; i++){for (j = i + 1; j < k; j++){if (brim[i].weight > brim[j].weight){Brim tmp = brim[i];brim[i] = brim[j];brim[j] = tmp;}}}int parent[MAXVEX] = { 0 };for (int i = 0; i < G->arcnum; i++){n = Find(parent, brim[i].start); //找到根節點 m = Find(parent, brim[i].end); //找到根節點 if (n != m)//m=n說明有環{parent[n] = m; //將根節點n所在的樹作為m的子樹 合并 brim[i].isUsed = 1;}printf("(%c,%c,%d,%d)", G->vex[brim[i].start], G->vex[brim[i].end], brim[i].weight, brim[i].isUsed);}}總結
以上是生活随笔為你收集整理的利用克鲁斯卡尔算法求最小生成树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: leetcode60.第k个排列java
- 下一篇: spring学习记录(一)