P1546 [USACO3.1]最短网络 Agri-Net(洛谷)

 

题目传送口

  很明显,这个题用邻接矩阵+dfs就能出(从不同点出发搜,且搜的时候更新最小值,可以剪枝,并且不成环) 。但算法标签中有并查集,因此此题尝试用并查集的方法来解决类似的连通图问题。

  核心算法:

    把每一条边按权值从小到大排序,然后依次看,如果两个端点不在一个集合里,就把他们合并,累加路径长度。如果已经包含所有点了,直接输出数据退出。(其实这也恰好是Kruskal算法的思想),在这里通过并查集来实现。

 

实现代码:

 

#include<bits/stdc++.h>
using namespace std;

int par[100];
int rank[100];
int n;
int len[101][101];
int ans=0;        //储存总路长 
int remain=0;
void init(){
    for(int i=1;i<=n;i++){
        par[i]=i;
        rank[i]=0;            //高度最初为0 
    }
}

int find(int x){
    if(par[x]==x){
        return x;
    }else return par[x]=find(par[x]);
}

void unite(int x,int y){
    x=find(x);
    y=find(y);
    if(x==y)    return;
    
    if(rank[x]<rank[y]){
        par[x]=y;
    }else{
        par[y]=x;
        if(rank[x]==rank[y]){
            rank[x]++;            //高度加1 
        }
    }
}

bool same(int x,int y){
    return find(x)==find(y);
}


typedef struct node{
    int length;        //保存长度
    int a;
    int b;            //保存两个端点 
}T;
T s[10000];

bool cmp(T k1,T k2){        //增序 
    return k1.length<k2.length;
}

int main(){
    cin>>n;
    remain=n-1;
    init();
    
    int t=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cin>>len[i][j];
            if(i>j){
                s[t].length=len[i][j];        //储存长度 
                s[t].a=i;                    //储存端点 
                s[t++].b=j;
            }
        }
    }
    
    sort(s,s+t,cmp);         //边进行排序 
    
    for(int i=0;i<t;i++){
        if(remain==0)    break;        //网络建完
        if(same(s[i].a,s[i].b)) continue;
        if(!same(s[i].a,s[i].b)){
            ans+=s[i].length;
            unite(s[i].a,s[i].b);        //进行合并
            remain--; 
        }
    }
    
    cout<<ans;
    return 0;
}

 

posted @ 2020-03-31 19:52  neverstopcoding  阅读(282)  评论(0编辑  收藏  举报