生成树 (tree)题解

题目描述

给定一个无向图,要求图中一个生成树,这个生成树中的最大边和最小边相差最小,输出这个差值

输入

第1行:输入两个整数n, m (3 ≤ n ≤ 300, 0 < m ≤ n*(n-1)/2),表示该组样例中点和边的个数,

之后每行三个整数x, y, s (0 ≤ x ≤ n-1, 0 ≤ y ≤ n-1, 1 ≤ s ≤ 10000),表示编号为x和编号为y的点之间有一条长度为s的边相连,保证给定的图联通,任意两点之间只有一条边相连

输出

输出最小差值,具体格式见sample

样例输入

【样例1】
3 3
0 1 220
1 2 120
2 0 160

【样例2】
4 5
2 3 80
1 3 80
0 1 180
2 1 200
3 0 140

样例输出

【样例1】
40

【样例2】
60

提示

数据范围 n m

1 ≤10 ≤45

2 ≤10 ≤45

3 ≤100 ≤4950

4 ≤100 ≤4950

5 ≤300 ≤20000

6 ≤300 ≤20000

7 ≤300 ≤44850

8 ≤300 ≤44850

9 ≤300 ≤44850

10 ≤300 ≤44850

想法

  • codevs1001 将边排序
  • 枚举起点不断将点加入最小生成树
  • 反过来再跑一遍

算法

  • 简单的kruskal

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#define MAXN 45011
#define INF 100000
using namespace std;
int n,m,tot,fa[305],ma,mi,ans,j,cnt;
//bool flag[MAXN];
struct Node
{
    int u,v,w,next;
}edge[MAXN];
inline bool cmp(Node a,Node b)
{
    return a.w<b.w;
}
inline int find(int a)
{
    if(fa[a]!=a)return find(fa[a]);
    else return fa[a];
}
int main()
{
    //freopen("tree.in","r",stdin);
    //freopen("tree.out","w",stdout);
    scanf("%d%d",&n,&m);
    ans=INF;
    for (int i=1;i<=m;i++)
        scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
    sort(edge+1,edge+1+m,cmp);
    for (int i=1;i<=m;)
    {
        mi=ma=-1;
        for (int k=0;k<n;k++)fa[k]=k;
        cnt=0;
        for (j=i;j<=m;j++)
        {
            int s=edge[j].u,t=edge[j].v;
            s=find(s),t=find(t);
            if(s!=t)
            {
                fa[s]=t,cnt++;
                if(cnt==n-1)
                {
                    ma=edge[j].w;
                    break;
                }
            }
        }
        if(ma==-1)break;
        cnt=0;
        for (int k=0;k<n;k++)fa[k]=k;
        for (;j;j--)
        {
            //printf("%d\n",j);
            int s=edge[j].u,t=edge[j].v;
            s=find(s),t=find(t);
            if(s!=t)
            {
                fa[s]=t,cnt++;
                if(cnt==n-1)
                {
                    mi=edge[j].w;
                    i=j+1;
                    break;
                }
            }
        }
        //printf("%d %d\n",mi,ma);
        if(mi==-1)break;
        ans=min(ans,ma-mi);
    }
    cout<<ans<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值