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

来源:互联网 发布:兴财软件 编辑:程序博客网 时间:2024/06/05 02:24

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


 

0 0