1. 程式人生 > >DS-7.1實現求最小生成樹的克魯斯卡爾演算法(並查集實現)

DS-7.1實現求最小生成樹的克魯斯卡爾演算法(並查集實現)

寫在前面:首先吐槽一下學校的OJ,題目上說是輸入字母結果後臺測試樣例卻出現數字= =!害得我改來改去提交了7次都是錯的。(呸

回到正題

題目描述
已知有權無向圖G,利用克魯斯卡爾演算法求出該圖的最小生成樹。
輸入
第一行輸入兩個正整數n和m(空格間隔), 分別表示圖G的頂點總數和邊的總數。
第二行連續輸入n個字母,分別表示n個頂點的資訊。
第三行連續輸入m條邊的資訊,每條邊的輸入格式為(v1,v2,w),表示一條關聯頂點v1和v2的邊,其權值為w。
輸出
按邊上權值由小到大的順序依次輸出各個邊。
輸出邊的時,若該邊被選中,則在該邊資訊之後輸出1,否則輸出0。
例如:
(v1,v2,w,1) 表示與頂點v1和v2相關聯的邊,權值為w,被選中。
(v1,v2,w,0) 表示與頂點v1和v2相關聯的邊,權值為w,未被選中。

解題思路

看到這道題,就是想到用鄰接矩陣來儲存,然後將題目資訊依次輸入。克魯斯卡爾演算法是將權重排序,然後從最小的開始取,如果不構成環就將邊加入,如果構成環就捨棄,也就是題目中說的1和0。最主要的問題就是我們要不停的檢查是否構成環,其實這裡應該可以用DFS來判斷連通分量(不會所以放棄了)。所以就採用了前幾天在部落格上看到的並查集。
並查集由一個整數型的陣列和兩個函式構成。陣列pre[]記錄了每個點的前導點是什麼,函式find是查詢,join是合併(這道題沒有用到)。

int Find(int *parent, int f) {
    while (parent[f] > 0) {
        f = parent
[f]; } return f; }

我們很容易通過並查集來判斷這些點是否都在一個集合裡,如果在的話就將邊捨棄,如果不在的話就放入。
剛學並查集,理解還不是很深刻,日後再補啦!
下面貼上本題程式碼

#include <iostream>
#include <cstring>
using namespace std;
#define MAXNUM 50
typedef struct {
    int vexnum;
    int arcsnum;
    char vertext[MAXNUM];
    int arcs[MAXNUM][MAXNUM];
} AdjMartix;
typedef
struct { int begin; int end; int weight; } Edge; using namespace std; AdjMartix *CreatAdjMartix(AdjMartix *G) { G = (AdjMartix *) malloc(sizeof(AdjMartix)); memset(G->arcs, 0, sizeof(G->arcs)); cin >> G->vexnum >> G->arcsnum; char ch1, ch2, a, b, c, d; int w; for (int i = 0; i < G->vexnum; i++) { cin >> G->vertext[i]; } for (int i = 0; i < G->arcsnum; i++) { cin >> a >> ch1 >> b >> ch2 >> c >> w >> d; if(ch1>='0'&&ch1<='9'&&ch2>='0'&&ch2<='9'){ G->arcs[ch1-'0'][ch2-'0']=w; } else{ G->arcs[ch1 - 'A' + 1][ch2 - 'A' + 1] = w; } } for(int i = 0; i < G->vexnum; i++) { for(int j = i; j < G->vexnum; j++) { G->arcs[j][i] =G->arcs[i][j]; } } return G; } int cmp(const void *a, const void *b) { return (*(Edge *) a).weight - (*(Edge *) b).weight; } int Find(int *parent, int f) { while (parent[f] > 0) { f = parent[f]; } return f; } void MiniSpanTree_Kruskal(AdjMartix *G) { int parents[MAXNUM]; Edge edge[MAXNUM]; int k = 0; int n, m; for (int i = 0; i < G->arcsnum - 1; i++) { for (int j = i + 1; j < G->arcsnum; j++) { if (G->arcs[i][j]) { edge[k].begin = i; edge[k].end = j; edge[k].weight = G->arcs[i][j]; k++; } } } qsort(edge, G->arcsnum, sizeof(Edge), cmp); memset(parents, 0, sizeof(parents)); for (int i = 0; i < G->arcsnum; i++) { n = Find(parents, edge[i].begin); m = Find(parents, edge[i].end); if (n != m) { parents[n] = m; cout << "(" << G->vertext[edge[i].begin - 1] << "," << G->vertext[edge[i].end - 1] << "," << edge[i].weight << "," << 1 << ")"; } if (n == m) { cout << "(" << G->vertext[edge[i].begin - 1] << "," << G->vertext[edge[i].end - 1] << "," << edge[i].weight << "," << 0 << ")"; } } } int main() { AdjMartix *adjMartix; adjMartix = CreatAdjMartix(adjMartix); MiniSpanTree_Kruskal(adjMartix); }