51NOD--2609 最苗条的生成树--生成树

2609 最苗条的生成树

  1. 1.0 秒
  2.  
  3. 131,072.0 KB
  4.  
  5. 20 分
  6.  
  7. 3级题

定义一颗树的苗条度为这棵树的最大边权与最小边权的差值。

现在有一个n个点m条边的无向联通图,求苗条度最小的生成树的苗条度是多少。

如图所示的数据中:最优的选取方案选取的生成树的三条边分别为(1-4,4-2,1-3),所以答案为100-80=20。

 收起

输入

第1行:两个正整数n,m,n表示图中点的个数,m表示图中边的个数。(2<=n<=100,0<=m<=(n*(n − 1)/2))
第2行-第m+1行:每行3个正整数,u,v,w,表示u和v之间有一条权值为w的边。(1<=u,v<=n,1<=w<=10000)

输出

输出一个整数表示苗条度最小的生成树的苗条度。

输入样例

4 6
1 2 10
1 3 100
1 4 90
2 3 20
2 4 80
3 4 40

输出样例

20

枚举最大最小值。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=20000+66;
const ll mod=1e9+7;
int N,M;
struct node
{
    int u;
    int v;
    int w;
} a[maxn];
bool cmp(const node&a,const node&b)
{
    return a.w<b.w;
}
int minn=9999999;
int f[maxn];
int finds(int x)
{
    return x==f[x]?x:f[x]=finds(f[x]);
}
void unions(int x,int y)
{
    int fx=finds(x);
    int fy=finds(y);
    if(fx!=fy)
    {
        f[fx]=fy;
    }
}
int work()
{
    for(int i=1; i<=N; i++)
        f[i]=i;
    int flag=0;
    for(int i=1; i<=M; i++)
    {
        int l=a[i].w;
        int r=l;
        int num=1;
        for(int k=1; k<=N; k++)
        f[k]=k;
        unions(a[i].u,a[i].v);
        for(int j=i+1; j<=M; j++)
        {
            if(finds(a[j].u)!=finds(a[j].v))
            {
                num++;
                unions(a[j].u,a[j].v);
                r=max(r,a[j].w);
            }
        }
        if(num==N-1)
        {
            flag=1;
            minn=min(minn,r-l);
        }
    }
    return minn;
}
int main()
{
    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);
    }
    sort(a+1,a+M+1,cmp);
    int ans1=work();
    printf("%d\n",ans1);//467  506
}
/*#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=20000+66;
const ll mod=1e9+7;
int N,M;
struct node
{
    int u;
    int v;
    int w;
} a[maxn];
bool cmp(const node&a,const node&b)
{
    return a.w<b.w;
}
int minn=9999999;
int f[maxn];
int finds(int x)
{
    return x==f[x]?x:f[x]=finds(f[x]);
}
void unions(int x,int y)
{
    int fx=finds(x);
    int fy=finds(y);
    if(fx!=fy)
    {
        f[fx]=fy;
    }
}
int work(int i1,int j1)
{
    for(int i=1; i<=N; i++)
        f[i]=i;
    int num=2;
    node x1=a[i1];
    node x2=a[j1];
    unions(x1.u,x1.v);
    unions(x2.u,x2.v);
    if(abs(x1.w-x2.w)>minn)return minn;
    for(int i=i1; i<=j1; i++)
    {
        // if(a[i].w<x1.w||a[i].w>x2.w)continue;
        if(num==N-1)
            break;
        if(finds(a[i].u)!=finds(a[i].v))
        {
            num++;
            unions(a[i].u,a[i].v);
        }
    }
    if(num==N-1)
    {
        minn=abs(x1.w-x2.w);
        return abs(x1.w-x2.w);
    }
    return 9999999;
}
int main()
{
    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);
    }
    sort(a+1,a+M+1,cmp);
    for(int i=1; i<=M; i++)
        for(int j=i+1; j<=M; j++)
                minn=min(minn,work(i,j));
    printf("%d\n",minn);//467  506
}*/

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值