道路建设 (Ver. I)

题目描述

有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之间的道路已经建成。

输出

对于每组测试数据

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

输入样例1
输出样例1
3
0 990 692
990 0 179
692 179 0
1
1 2
179

 提示:样例里的修路记录中有重复的部分,别被假路卡住啦/悲

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;

struct node{
    int va,vb,weight;
};

class country_road{

    int num;
    int**st;

public:
    country_road(){}
    country_road(int n,int **s){
        num = n;
        st = new int *[num];
        for(int i = 0 ; i < num ; i++ ){
            st[i] = new int [num];
            for(int j = 0 ; j < num ; j++ ){
                st[i][j] = s[i][j];
            }
        }
    }
    void kruskal(node *r,int r_t);
    bool static cmp(node t1,node t2);
};
void country_road::kruskal(node *r,int r_t){
    int len = num*(num-1)/2;

    int *v = new int [num];
    for(int i = 0 ; i < num ; i++ ){
        v[i] = i;
    }

    int del=0;
    node *test = new node [len];
    for(int i = 0 ,pos = 0; i < num ; i++ ){
        for(int j = i+1 ; j < num ; j++ ){

            test[pos].va = i;test[pos].vb = j ; test[pos].weight = st[i][j];

            if(v[i]!=v[j])
                for(int k = 0 ; k < r_t ; k++){
                    if(r[k].va-1==i&&r[k].vb-1==j){
                        test[pos].weight = 0;del++;
                        for(int z = 0 ; z < num ; z++ ){
                            if(z!=i&&v[z] == v[i]){
                                v[z] = v[j];
                            }
                        }
                        v[i] = v[j];
                        break;//*降重*防止旧路记录中有重复记录
                    }

                }

            pos++;
        }
    }
    sort(test,test+len,cmp);

    int sum=0;
    for(int i = 0 ,k = 0; i < len&&k<num-1-del ; i++ ){

        if(v[test[i].va]!=v[test[i].vb]){
            //省略造图
            k++;
            sum+=test[i].weight;
            for(int j = 0 ; j < num ; j++ ){
                if(j!=test[i].va&&v[j] == v[test[i].va]){
                    v[j] = v[test[i].vb];
                }
                v[test[i].va]=v[test[i].vb];
            }
        }


    }
    cout<<sum;

}
bool country_road::cmp(node t1,node t2){
    return t1.weight<t2.weight;
}
int main(){

    int t;
    int flag =0;
    while(cin>>t){
        if(flag == 1)
            cout<<endl;
        flag = 1;
        int **s = new int *[t];
        for(int i = 0 ; i < t ; i++ ){
            s[i] = new int [t];
            for(int j = 0 ; j < t ; j++ ){
                cin>>s[i][j];
            }
        }
        country_road c_r(t,s);
        int q;
        cin>>q;
        node *r = new node [q];
        for(int i  = 0 ; i < q ; i++ ){
            cin>>r[i].va>>r[i].vb;r[i].weight = s[r[i].va-1][r[i].vb-1];
            if(r[i].va>r[i].vb)
                swap(r[i].va,r[i].vb);
        }
        c_r.kruskal(r,q);
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值