12.5克鲁斯卡尔算法

题目描述

有N个村庄,编号从1到N,你应该建造一些道路,使每个村庄都可以相互连接。

两个村A和B是相连的,当且仅当A和B之间有一条道路,或者存在一个村C使得在A和C之间有一条道路,并且C和B相连。

现在一些村庄之间已经有一些道路,你的任务就是修建一些道路,使所有村庄都连通起来,并且所有道路的长度总和是最小的。

输入

测试数据有多组

第一行是整数N(3 <= N <= 100),代表村庄的数量。 然后是N行,其中第i行包含N个整数,这些N个整数中的第j个是村庄i和村庄j之间的距离(距离是[1,1000]内的整数)。

然后是整数Q(0 <= Q <= N *(N + 1)/ 2),接下来是Q行,每行包含两个整数a和b(1 <= a <b <= N),代表着村庄a和村庄b之间的道路已经建成。

输出

对于每组测试数据

输出一个整数,表示要构建的道路的长度总和最小值

样例输入

3 0 990 692 990 0 179 692 179 0 1 1 2

样例输出

179

#include<iostream>
using namespace std;
struct com {
    int fis;
    int sec;
    int weight;
};
class Graph
{
private:
    int** martix, * group;//group存放所在连通图
    int n, len; //n 是节点个数 len是边的数
    int sum = 0;;
    com* sort;//设置排序数组
    int* visited;//设置访问节点
    int way;
public:
    Graph() {};
    void SetGraph(int n);
    void kruskal();
    void show();
    void connect();//设置联通函数
};
void Graph::SetGraph(int _n){
    int i, j;
    n = _n;
    way = (n * (n - 1)) / 2;
    martix = new int* [n + 1];
    group = new int[n + 1];
    visited = new int[n + 1];
    for (i = 1; i <= n; i++)//输入矩阵
    {
        martix[i] = new int[n + 1];
        group[i] = i;
        visited[i] = false;
        for (j = 1; j <= n; j++)
        {
            cin >> martix[i][j];
        }
    }
    connect();
}
void Graph::connect() {//将连接的点村庄置于同一连通图
    cin >> len;
    for (int i = 1; i <= len; i++)
    {
        int to1, to2;
        cin >> to1 >> to2;
        if (group[to2] != group[to1]) {//在不同的连通图时
            if (!visited[to2]) {
                group[to2] = group[to1];
                visited[to2] = true;
                visited[to1] = true;
            }
            else if (visited[to2] && !visited[to1]) {
                group[to1] = group[to2];
                visited[to1] = true;
            }
            else if (visited[to2] && visited[to1]) {
                int temp = group[to2];
                for (int i = 1; i <= n; i++) {//确保所在连通图所有点全部置于同一连通图
                    if (group[i] == temp)
                        group[i] = group[to1];
                }
            }
        }
    }
}
void Graph::kruskal()
{
    sort = new com[way+1];
    int fis = -1, sec = -1;
    int temp;
    for (int i = 0; i <= way; i++) {//sort数组
        sort[i].fis = fis;
        sort[i].sec = sec;
        int temp = 9999;
        if (fis != -1) {
            sort[i].weight = martix[sec][fis];
            martix[sec][fis] = 9999;
        }
        for (int j = 1; j <= n; j++) {
            for (int k = 1; k < j; k++) {
                if (temp > martix[j][k]) {
                    temp = martix[j][k];
                    fis = k;
                    sec = j;
                }
            }
        }
    }
    for (int i = 1; i <= way; i++) {
        int fis = sort[i].fis;
        int sec = sort[i].sec;
        if (group[fis] != group[sec])
        {
            sum += sort[i].weight;
            int temp = group[sec];
            for (int i = 1; i <= n; i++) {//确保所在连通图所有点全部置于同一连通图
                if (group[i] == temp)
                    group[i] = group[fis];
            }
        }
    }
}
void Graph::show()
{
    cout << sum << endl;
}
int main()
{
    int n;
    while (cin>>n) {
        Graph m;
        m.SetGraph(n);
        m.kruskal();
        m.show();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值