贪心思想——Kruskal

贪心思想——Kruskal

求最小生成数还有另一种算法,Kruskal

Kruskal算法运用了贪心的思想,首先是对得到的边集数组进行排序,权值小的边排在前面,这是为之后的贪心做准备工作

Kruskal算法的核心思想是:根据权值从小到大遍历每一条边,把原图分为两个集合,每一次判断这一条边的两个端点是否在同一集合,为真,则表明这个点已经在MST中,由于贪心,所以最优,故跳过;为假,则表明这个点并未在集合之中,所以将该点加入集合中(运用并查集来实现)。因为一个有n个点的图,最小生成树只需n-1条边,所以标记一下,如果已经选出了n-1条边,break;若最后遍历了整个图,仍为选出n-1条边,输出无解


题目——修复公路

描述:

A地区在地震过后,连接所有村庄的公路都造成了损坏而无法通车。政府派人修复这些公路。给出A地区的村庄数N,和公路数M,公路是双向的。并告诉你每条公路的连着哪两个村庄,并告诉你什么时候能修完这条公路。

问最早什么时候任意两个村庄能够通车,即最早什么时候任意两条村庄都存在至少一条修复完成的道路(可以由多条公路连成一条道路)

input:

第1行两个正整数N,M(N<=1000,M<=100000)

下面M行,每行3个正整数x, y, t,告诉你这条公路连着x,y两个村庄,在时间t时能修复完成这条公路。(x<=N,y<=N,t<=100000)

output:

如果全部公路修复完毕仍然存在两个村庄无法通车,则输出-1,否则输出最早什么时候任意两个村庄能够通车

sample.in:

4 4

1 2 6

1 3 4

1 4 5

4 2 3

sample.out:

5


接下来上代码

#include<iostream>
#include<algorithm>
using namespace std;
int n,m;
int f[200000];
struct node
{
    int x,y,t;
}a[200000];
int getfather(int x)
{
    if(f[x]==x)
    {
        return x;
    }
    else return f[x]=getfather(f[x]);
}
int cmp(node a,node b)
{
    return a.t<b.t;
}
int ans;
int k;
int maxx=0;
void kruskal()
{
    int fa1,fa2;
    for(int i=1;i<=m;i++)
    {
        fa1=getfather(a[i].x);
        fa2=getfather(a[i].y);
        if(fa1!=fa2)
        {
            maxx=max(maxx,a[i].t);
            ans+=a[i].t;
            f[fa1]=fa2;
            k++;
            if(k==n-1)break;
        }
    }
    if(k<n-1)
    {
        cout<<"-1";
        return;
    }
    cout<<maxx<<endl;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>a[i].x>>a[i].y>>a[i].t;
    }
    for(int i=1;i<=n;i++)
    {
        f[i]=i;
    }
    sort(a+1,a+m+1,cmp);
    kruskal();
}

猜你喜欢

转载自www.cnblogs.com/boruto/p/9556480.html