HDU4313,kruskal算法,并查集

题目给出了几个点,去掉生成树中的边,使这几个点相互孤立,求去掉的边的总长度之和最小。如果顺着题目的思路去想,可能有点难得想,此时可以尝试换一个思路:模拟建树的过程。首先随便取两个点,如果这两个点需要相互孤立,那么就不取它们之间的边,反之则取。用并查集来判断两个点是否需要相互孤立。最后用总的边的长度减去取的边的长度,就是答案了,在此之前将边从大到小排个序比较好,这样才能保证去掉的是最小长度嘛。我用的是优先队列,当然用数组排序是一样的。

/*************************************************************************
    > File Name: main.cpp
    > Author:Eagles 
    > Mail:None 
    > Created Time: 2018年09月05日 星期三 11时09分01秒
    > Description:HDU4313,kruskal,并查集 
 ************************************************************************/

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;//用int会wa
ll n,m;
#define N 100005
ll par[N];
ll dst[N];//用来保存需要相互孤立的点
ll sum;
struct node
{
    ll a,b;
    ll val;
    bool operator <(node com) const
    {
        return val<com.val;
    }
};
priority_queue<node>Q;

ll find_par(ll x)
{
    return x==par[x]?x:par[x]=find_par(par[x]);
}

void unite(ll x, ll y)
{
    ll fx=find_par(x);
    ll fy=find_par(y);
    par[fy]=fx;
}

void init()
{
    for (ll i=0; i<=n; i++)
        par[i]=i;

    sum=0;//总的长度

    for (ll i=0; i<n-1; i++)
    {
        node E;
        scanf("%lld%lld%lld",&E.a,&E.b,&E.val);
        sum+=E.val;
        Q.push(E);
    }

    for (ll i=0; i<m; i++)
        scanf("%lld",&dst[i]);

    for (ll i=1; i<m; i++)
        unite(dst[0],dst[i]);都以第一个点为父节点,在该集合中的点需要相互孤立
}

void kruskal()
{
    ll the_max=0;//保存可取的边


    while (!Q.empty())
    {
        node E=Q.top();
        Q.pop();

        ll fa=find_par(E.a);
        ll fb=find_par(E.b);

        if (fa != fb)//这两个点属于不同的阵营,说明这两个点肯定不会相互孤立
        {
            if (fb==dst[0])//如果有一个点属于需要孤立的点的集合,那么就将不需要孤立点的父节点设为dst[0]
                swap(fa,fb);

            unite(fa,fb);
            the_max+=E.val;
            continue;
        }
    }

    printf("%lld\n",sum-the_max);
}

int main()
{
    ll t;
    while (~scanf("%lld",&t))
    {
        while (t--)
        {
            scanf("%lld%lld",&n,&m);
            init();
            kruskal();
        }
    }
    return 0;
}

发布了45 篇原创文章 · 获赞 2 · 访问量 3100

猜你喜欢

转载自blog.csdn.net/wysiwygo/article/details/82422245