这个算法结合并查集,相较于另一个算法而言,这个相对于我来说理解起来更加容易。

最小生成树-Kruskal算法

就上面的图来说,假如说1/2/3/4/5/6分别代表不同的商店,这些商店我都要过去,而我去这些商店的时候,又需要不同的车费,让求怎么走才能使得车费少。

这个就是最小生成树所要解决的问题,选择最少的车费。

1、将车费从小到大排序,然后我们的选择顺序就是这个顺序

2、运用并查集的思想(先判断两点是否能够构成环或者说有没有共同的祖先,如果有的话就过,反之,就把这条路计算到里面,然后让走过的边的数量加一,如果边的数量等于商店数量减一就结束)

#include<stdio.h>
#include<algorithm>
using namespace std;

struct xiao
{
    int u,v,w;
}a[100];

int father[100];

void quicksort(int x,int y)
{
    //分别代表的是左端点和右端点
    struct xiao t;

    int left=x;
    int right=y;
    if(left>right) return ;
    int index=a[left].w;
    while(left!=right)//现在需要知道的是一个已经排完序的情况
    {
        while(a[right].w>=index&&left<right)
        {
            right--;
        }
        while(a[left].w<=index&&left<right)
        {
            left++;
        }
        if(left<right)
        {
            t=a[left];
            a[left]=a[right];
            a[right]=t;
        }
    }
    //最终将基准数归位。
    t=a[x];
    a[x]=a[left];
    a[left]=t;

    quicksort(x,left-1);
    quicksort(left+1,y);
    return ;
}

int Find(int x)
{
    if(x!=father[x])
    {
      father[x]=Find(father[x]);
    }
    return father[x];
}

int combine(int x,int y)
{
    int fx=Find(x);
    int fy=Find(y);
    if(fx!=fy)
    {
        father[fx]=fy;
        return 1;
    }
    return 0;
}

int main()
{
    int n,m,number=0,outputs=0;//n个点,m条路
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i)
        scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
    for(int i=1;i<=n;++i)
        father[i]=i;
    quicksort(1,m);
    //已经排好序了!
//    for(int i=1;i<=m;++i)
//        printf("%d\n",a[i].w);
    for(int i=1;i<=m;++i)
    {
        if(combine(a[i].u,a[i].v))
        {
            ++number;
            outputs+=a[i].w;
        }
        if(number==n-1)
            break;
    }
    printf("%d\n",outputs);
    return 0;
}

//6 9
//2 4 11
//3 5 13
//4 6 3
//5 6 4
//2 3 6
//4 5 7
//1 2 1
//3 4 9
//1 3 2

 

相关文章: