DS-7.1实现求最小生成树的克鲁斯卡尔算法(并查集实现)

来源:互联网 发布:印度现状 知乎 编辑:程序博客网 时间:2024/05/18 09:45

写在前面:首先吐槽一下学校的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 50typedef 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);}
阅读全文
1 0