DS-7.1實現求最小生成樹的克魯斯卡爾演算法(並查集實現)
阿新 • • 發佈:2019-02-08
寫在前面:首先吐槽一下學校的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);
}