wikioi-天梯-通过初赛-最小生成树-1078:最小生成树

农民约翰被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场。当然,他需要你的帮助。 约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场。为了使花费最少,他想铺设最短的光纤去连接所有的农场。 你将得到一份各农场之间连接费用的列表,你必须找出能连接所有农场并所用光纤最短的方案。 每两个农场间的距离不会超过100000

第一行: 农场的个数,N(3<=N<=100)。

第二行..结尾: 接下来的行包含了一个N*N的矩阵,表示每个农场之间的距离。理论上,他们是N行,每行由N个用空格分隔的数组成,实际上,他们每行限制在80个字符以内,因此,某些行会紧接着另一些行。当然,对角线将会是0,因为线路从第i个农场到它本身的距离在本题中没有意义。

只有一个输出,是连接到每个农场的光纤的最小长度和。

4

0  4  9 21

4  0  8 17

9  8  0 16

21 17 16  0

类型:图论  难度:1.5

题意:给出图的邻接矩阵,求最小生成树

分析:比较清晰的基本题,这里我用kruskal算法,将图中所有边按长度排序,从小到大选择, 如边的两点尚未连通,则将边加入,记录结果。

注意:判断两个点是否已经连通的方法,用f[i]记录i所在连通分支形成的树的父亲,初始化f[i]=i。若将i,j两个连通分支合并,则令f[f[i]] = f[f[j]],每次通过f数组找到i,j所在连通分支的根节点,若相同,则i,j连通,否则不连通。

优化:上述方法很可能造成连通分支形成的树为退化树(每个节点只有一个子节点,退化为单链表),而上述问题实际上是一个合并等价类的问题,数据结构书中有union和find的优化操作,写的很清楚,这里就不赘述了。

代码:

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;

int n;
struct node
{
    int len,x,y;
    bool operator < (node b) const
    {
        return len > b.len;
    }
    bool operator > (node b) const
    {
        return len < b.len;
    }
    bool operator == (node b) const
    {
        return len == b.len;
    }
};
priority_queue<node> qu;
int f[110];

int find(int x)
{
    return f[x]==x ? x: find(f[x]);
}

int main()
{
    cin>>n;
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
        {
            int len;
            cin>>len;
            if(!len) continue;
            node now;
            now.len = len;
            now.x = i;
            now.y = j;
            qu.push(now);
        }
    for(int i=0; i<n; i++)
        f[i] = i;

    int ans = 0,cnt = 1;
    while(cnt<n)
    {
        node now = qu.top();
        qu.pop();
        
        int xc = find(now.x);
        int yc = find(now.y);
        
        if(xc == yc)
            continue;
        ans += now.len;
        cnt++;
        f[xc] = yc;
    }
    cout<<ans<<endl;
}


 

你可能感兴趣的:(最小生成树,kruskal,WIKIOI,天梯)