Prim算法求最小生成树

#include <iostream>
#include <climits> /* for INT_MAX */
using namespace std;
/** 顶点数最大值. */
const int MAX_NV = 100;
/** 边的权值类型,可以为int, float, double. */
typedef int graph_weight_t;
const graph_weight_t GRAPH_INF = INT_MAX;
/**
* @struct 图,用邻接矩阵(Adjacency Matrix).
*/
struct graph_t {
    int nv; // 顶点数
    int ne; // 边数
    // 邻接矩阵,存放边的信息,如权重等
    graph_weight_t matrix[MAX_NV][MAX_NV];
};
graph_t g;
struct closedge_t {
    int adjvex; /* 弧尾,属于U,注:弧尾是弧的起点,弧头是弧的终点,因为终点带有箭头,所以叫弧头 */
    /* 边adjvex-> 本下标的权值,-GRAPH_INF 表示已经加入U */
    graph_weight_t lowcost;
};
/*
* @brief 在V-E 集合中寻找最小的边
* @param[in] closedge MST 中的边,起点为adjvex,终点为本下标
* @param[in] n closedge 数组的长度
* @return 找到了则返回弧头的下标,V-U 为空集则返回-1,表示终止
*/
static int min_element(const closedge_t closedge[], int n) {
    int min_value = GRAPH_INF;
    int min_pos = -1;
    for (int i = 0; i < n; i++)
        if (closedge[i].lowcost > -GRAPH_INF) {
            if (min_value > closedge[i].lowcost) {
                min_value = closedge[i].lowcost;
                min_pos = i;
            }
        }
        return min_pos;
}
/**
* @brief Prim 算法,求图的最小生成树.
* @param[in] g 图对象的指针
* @return MST 的边的权值之和
*/
graph_weight_t prim(const graph_t &g) {
    graph_weight_t sum = 0; /* 权值之和*/
    int u = 0; /* 从0 号顶点出发*/
    const int n = g.nv;
    /* closedge[n],记录从顶点集U 到V-U 的边*/
    closedge_t* const closedge = new closedge_t[n];
    /* 辅助数组初始化*/
    for (int i = 0; i < n; i++) if (i != u) {
        closedge[i].adjvex = u;
        closedge[i].lowcost = g.matrix[u][i];
    }
    closedge[u].lowcost = -GRAPH_INF; /* 初始, U={u} */
    for (int i = 0; i < n; i++) if (i != u) { /* 其余的n-1 个顶点*/
        /* 求出TE 的下一个顶点k */
        const int k = min_element(closedge, n);
        /* 输出此边closedge[k].adjvex --> k */
        cout << (char)('A' + closedge[k].adjvex) << " - " << (char)('A' + k)
            << " : "<< g.matrix[closedge[k].adjvex][k] << endl;
        sum += g.matrix[closedge[k].adjvex][k];
        // sum += closedge[k].lowcost; // 等价
        closedge[k].lowcost = -GRAPH_INF; /* 顶点k 并入U,表示此边加入TE */
        /* 更新k 的邻接点的值,不相邻为无穷大*/
        for (int j = 0; j < n; j++) {
            const graph_weight_t w = g.matrix[k][j];
            if (w < closedge[j].lowcost) {
                closedge[j].adjvex = k;
                closedge[j].lowcost = w;
            }
        }
    }
    delete[] closedge;
    return sum;
}
/** 读取输入,构建图. */
void read_graph() {
    int m, n;
    /* 读取节点和边的数目*/
    cin >> m >> n;
    g.nv = m;
    g.ne = n;
    /* 初始化图,所有节点间距离为无穷大*/
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < m; j++) {
            g.matrix[i][j] = GRAPH_INF;
        }
    }
    /* 读取边信息*/
    for (int k = 0; k < n; k++) {
        char chx, chy;
        int w;
        cin >> chx >> chy >> w;
        const int i = chx - 'A';
        const int j = chy - 'A';
        g.matrix[i][j] = w;
        g.matrix[j][i] = w;
    }
}

int main() {
    read_graph();
    cout << "Total : " << prim(g) << endl;
    return 0;
}

/* test
输入数据:
7 11
A B 7
A D 5
B C 8
B D 9
B E 7
C E 5
D E 15
D F 6
E F 8
E G 9
F G 11
输出:
A - D : 5
D - F : 6
A - B : 7
B - E : 7
E - C : 5
E - G : 9
Total:39
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值