Kruskal算法

铁路管理局新增 7 个站点 (A, B, C, D, E, F, G) ,现在需要修路把 7 个站点连通,各个站点的距离用边线表示 ( 权 ) ,比如 A – B 距离 12 公里

问:如何修路保证各个站点都能连通,并且总的修建铁路总里程最短 ?

基本思想 :按照权值从小到大的顺序选择 n-1 条边,并保证这 n-1 条边不构成回路

具体做法 :首先构造一个只含 n 个顶点的森林,然后依权值从小到大从连通网中选择边加入到森林中,并使森林中不产生回路,直至森林变成一棵树为止

 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_VERTEX 10//最多顶点个数
#define MAX_EDGE 100//最多边个数
typedef int DataType;
 
typedef struct EdgeType {
    int from, to; //边依附的两个顶点
    int weight;//边上的权值
} EdgeType;
 
struct EdgeGraph {
    DataType vertex[MAX_VERTEX];//存放图顶点的数据
    EdgeType edge[MAX_EDGE];//存放边的数组
    int vertexNum, edgeNum; //图的顶点数和边数
};
 
main() {
    int vertexNum, arcNum; //顶点个数,边的个数
    printf("请输入顶点个数和边的个数:");
    scanf("%d %d", &vertexNum, &arcNum);
    struct EdgeGraph graph;
    Graph(&graph, vertexNum, arcNum);
    ranklist(&graph);
    printf("输出通过边信息储存的图:\n");
    printGraph(graph);
    int parent[vertexNum];//每一个结点的双亲结点(根结点)
    printf("输出Kruskal算法得的最小生成树(from,to)weght:\n");
    Kruskal(graph, parent);
}
 
void Graph(struct EdgeGraph *graph, int vertexNum, int arcNum) {
    graph->edgeNum = arcNum;
    graph->vertexNum = vertexNum;
    printf("请逐个输入顶点的内容:");
    DataType x;
    for (int i = 0; i < vertexNum; i++) { //顶点数组赋值
        scanf("%d", &x);
        graph->vertex[i] = x;
    }
    int count = 1;
    int a, b, ave;
    for (int i = 0; i < arcNum; i++) { //依次输入每一条边
        printf("请输入第%d条边依附的两个顶点的编号和权值:", count++);
        scanf("%d %d %d", &a, &b, &ave); //输入该边依附的顶点的编号
        graph->edge[i].from = a;
        graph->edge[i].to = b;
        graph->edge[i].weight = ave;
    }
}
 
void ranklist(struct EdgeGraph *graph) { //将图的边数组按边的权值从小到大排序
    EdgeType temp;
    for (int i = 0; i < graph->edgeNum ; i++) { //冒泡排序
        for (int j = 0; j < graph->edgeNum  - i - 1; j++) {
            if (graph->edge[j].weight > graph->edge[j + 1].weight) {
                temp = graph->edge[j];
                graph->edge[j] = graph->edge[j + 1];
                graph->edge[j + 1] = temp;
            }
        }
    }
}
 
void Kruskal(struct EdgeGraph graph, int *parent) {
    for (int i = 0; i < graph.vertexNum; i++)
        parent[i] = -1; //初始化双亲数组,值为-1代表本身为根结点
    int num, i, vex1, vex2;
    for (num = 0, i = 0; i < graph.edgeNum; i++) {
        vex1 = findRoot(parent, graph.edge[i].from); //找到所在生成树的根结点
        vex2 = findRoot(parent, graph.edge[i].to); //找到所在生成树的根结点
        if (vex1 != vex2) { //找到的两个根结点不同,不会构成环
            outputMST(graph.edge[i]);//输出加入的边
            parent[vex2] = vex1; //合成生成树
            num++;
            if (num == graph.vertexNum - 1) //循环了“图的顶点数-1”次,提前返回
                return;
        }
 
    }
}
 
int findRoot(int *parent, int v) {
    int t = v;
    while (parent[t] > -1)
        t = parent[t]; //求顶点t上的双亲直达根结点
    return t;
}
 
void outputMST(EdgeType x) {
    printf("(%d,%d)%d\n", x.from, x.to, x.weight);
}
 
void printGraph(struct EdgeGraph graph) {
    printf("   no     from   to   weight\n");
    for (int i = 0; i < graph.edgeNum; i++) {
        printf("  edge[%d]  %d      %d      %d\n", i, graph.edge[i].from, graph.edge[i].to, graph.edge[i].weight);
    }
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值