还是畅通工程(最小生成树)

问题描述

某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。

输入

测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。

输出

对每个测试用例,在1行里输出最小的公路总长度。

Sample Input

3 1 2 1 1 3 2 2 3 4 4 1 2 1 1 3 4 1 4 1 2 3 3 2 4 2 3 4 5 0

 

Sample Output

3 5


Sample Input      

3  (1 2 1) (1 3 2) (2 3 4)                               

4  (1 2 1 )(1 3 4) (1 4 1) (2 3 3) (2 4 2) (3 4 5)

0

连通并且最短距离,显然是最小生成树问题。

最小生成树问题有两种基本解决算法:

(1)prim算法(加点法)

(2)kruskal算法(加边法)

法一:prim算法

    加点法。

   初始化点1,设置为已访问visit[1]=1。将每个未访问点到访问点的最短距离初始化为到点1 的距离,dis[j]=map[1][j]。

   不断选择未访问到访问点的最短距离dis[n],加入最短距离,将最短距离的点设置为已访问。

   重新计算每个未访问点的最短距离。

   对n-1个点进行选择。(n-1次循环)

#include <stdio.h>
#include <string.h>
#define MAXN 100000
#define N 110

int map[N][N];
int visit[N];
int dis[N];
int prime(int n)
{
    int i,j,min,k,s=0;
    memset(visit,0,sizeof(visit));
    for(i=1;i<=n;i++)
        dis[i]=map[1][i];
    visit[1]=1;
    for(i=1;i<n;i++)      //n-1个点
    {
        min=MAXN;
        for(j=1;j<=n;j++)
        {
            if(visit[j]==0&&dis[j]<min)    //从1出发选择一条最短的路
            {
                min=dis[j];
                k=j;
            }
        }
        visit[k]=1;                        //k也访问过了,更新所有未访问过的最短距离
        s=s+dis[k];
        for(j=1;j<=n;j++)
        {
            if(visit[j]==0&&dis[j]>map[k][j])
            {
                dis[j]=map[k][j];
            }
        }
    }
    return s;
}

int main()
{
    int n,i,j,x,y,s,m,sum=0;
    while(scanf("%d",&n))
    {
        if(n==0) break;
        for(i=0;i<=n;i++)
            for(j=0;j<=n;j++)
                map[i][j]=MAXN;
        m=n*(n-1)/2;

        while(m--)
        {
            scanf("%d %d %d",&x,&y,&s);

            map[x][y]=map[y][x]=s;
        }
        sum=prime(n);
        printf("%d\n",sum);

    }
    return 0;
}

法二:kruskal算法

加边法。在这里我使用了并查集,来判断新加入的边的两点是否已经连通。

对所有的边进行排序,从小到大 的选择边,判断即将加入的边的两点是否已经连通,是则不加入,否则加入。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 10000

typedef struct _node{
    int val;
    int start;
    int end;
}Node;

Node V[N];
int f[N];

void init(int n)
{
    int i;
    for(i=1;i<=n;i++)
       f[i]=i;
}
int find(int x)
{
    while(x!=f[x])
        x=f[x];
    return x;
}
void merge(int x,int y)
{
    int xx=find(x);
    int yy=find(y);
    if(x!=y)
        f[xx]=yy;
}

int kruskal(int n)
{
    int i,x,y,s=0;
        int m=n*(n-1)/2;
    init(n);
    for(i=0;i<m;i++)
    {
        x=V[i].start;
        y=V[i].end;
        if(find(x)!=find(y))
        {
            merge(x,y);
            s+=V[i].val;
        }

    }
    return s;
}
void initv(int m)
{
    int i,x,y,s;
    for(i=0;i<m;i++)
    {
        scanf("%d %d %d",&x,&y,&s);
        V[i].start=x;
        V[i].end=y;
        V[i].val=s;
    }

}

int cmp(const void *a, const void *b)
{
   return(*(Node *)a).val - (*(Node*)b).val;
}

int main()
{
    int n,i,j,x,y,s,m,sum=0;
    while(scanf("%d",&n))
    {
        if(n==0) break;
        int m=n*(n-1)/2;
        initv(m);
        qsort(V,m,sizeof(V[0]), cmp);
        sum=kruskal(n);

        printf("%d\n",sum);

    }
    return 0;
}
发布了46 篇原创文章 · 获赞 15 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/sinat_34686158/article/details/82353936