HDU 5624 KK's Reconstruction(最小生成树-Kruskal)

Description
我们可爱的KK有一道困难的社会性题目:他所在的地区发生了一场大地震(如此老套的出题思路~!),一共有N(2≤N≤2000)个城市受到了牵连,N个城市间所有道路都已损坏,现在KK受委托要重修这些道路。然而,经过KK的实地考察发现,很多城市间道路的地基都被破坏了,无法再重修道路,因此可供修建的道路只有M(0≤M≤15000)条。KK要用尽量少的道路将所有的城市联通起来,在此条件下,他希望选择一种方案,使得方案中最贵道路的价格和最便宜道路的价格的差值最小。
Input
第一行一个数T(1≤T≤10),表示数据组数。
每组数据第一行包含两个整数N(2≤N≤2000),M(0≤M≤15000),表示城市的个数和可重修的道路条数。
接下来M行,每行包含三个整数a,b,c(a≠b,1≤c≤2∗10​^9),表示城市a,b之间可以修建一条价格为c的无向道路。
Output
对于每一个数据输出一个整数,表示最贵道路的价格和最便宜道路的价格的最小差值,如果不存在合法的方案,则输出-1。
Sample Input
2
5 10
1 2 9384
1 3 887
1 4 2778
1 5 6916
2 3 7794
2 4 8336
2 5 5387
3 4 493
3 5 6650
4 5 1422
2 0
Sample Output
1686
-1
Solution
虽然一个图的最小生成树不唯一,但是这些最小生成树的边权一定是一一对应的,也就是说当一个图的最小生成树的最小边唯一确定时,其最大边权值也被唯一确定了,那么此题我们将边排序后枚举最小边,用Kruskal求出最小生成树的最大边更新最优解即可,注意当枚举到某条边时已经形不成最小生成树时后面也不会再形成最小生成树了(图已经不连通了),这时直接退出循环即可
Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 2222
#define maxm 15555
struct node
{
    int u,v,w;
}edge[maxm];
int T,n,m,fa[maxn];
int cmp(node a,node b)
{
    if(a.w!=b.w)return a.w<b.w;
    if(a.u!=b.u)return a.u<b.u;
    return a.v<b.v;
}
int find(int x)
{
    if(fa[x]==x) return x;
    return fa[x]=find(fa[x]);
}
int kruskal(int s)
{
    for(int i=1;i<=n;i++)fa[i]=i;
    int ans=edge[m-1].w,cnt=0;
    for(int k=s;k<m;k++)
    {
        int x=find(edge[k].u),y=find(edge[k].v);
        if(x!=y)
        {
            cnt++;
            fa[x]=y;
            if(cnt==n-1)return edge[k].w-edge[s].w;
        }
    }
    return -1;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++)
            scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
        sort(edge,edge+m,cmp);
        int ans=kruskal(0);
        if(ans==-1)printf("-1\n");
        else
        {
            for(int i=1;i<m;i++)
            {
                int temp=kruskal(i);
                if(temp==-1)break;
                ans=min(ans,temp);
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值