Uva1395 Slim Span(最小生成树)

题意:

给定一个无向图G(V,E),要求建图使得两点之间有且只有一条连通的道路,即最小生成树。输出最大边权值减最小边权值的差的最小值(苗条度)。
这里写图片描述
如图所示,(a) = 7-3=4; (b) = 6-3 =3; (c) = 7-5 = 2; (d) = 7-6=1;

解题思路:

根据图中的信息可知,连通的方式有许多种,所以我们需要枚举所有可能连通的方案。
首先将每个边按照权值从小到大排序。然后依次枚举区间[L,R]。
总共m条边。
例如:若第1条边到第m边能构成连通图,则苗条度肯定不会超过W[m]-W[i]。
于是我们从第2条边开始枚举到第m条边,依次类推。
分成三步骤:
1: 枚举并查集
2:利用并查集将所有点连通。
3:在连通的基础上找到最大边权值减最小边权值的差的最小值。

具体代码

#include <set>
#include <numeric>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cctype>
#include <string>
#include <sstream>
#include <map>
#include <functional>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define REP(idx1,num1) for(int idx1=0;idx1<(num1);idx1++)
#define pb push_back
#define empb emplace_back
#define mp make_pair
#define mem(s) memset(s,0,sizeof(s));
const double EPS = 1e-6;
const int maxn = 100 + 10;
int p[maxn];
struct Edge{
    int from,to,w;
}edge[maxn*maxn];
int cmp(Edge i, Edge j){ return i.w < j.w;}
int find(int x){
    int t = x;
    while(p[t] != t) t = p[t];
    int i = x,j;
    //路径优化
    while(i != t){
        j = p[i];
        p[i] = t;
        i = j;
    }
    return t;
}
void init(int n){
    for(int i = 1; i <= n; ++i) p[i] = i;
}
int main(){
    int n,m;
    while(~scanf("%d%d",&n,&m)&&n){

        for(int i = 1; i <= m; ++i){
            int a,b,w;scanf("%d%d%d",&a,&b,&w);
            if(a > b)swap(a,b);
            edge[i].from = a;edge[i].to = b;edge[i].w = w;
        }
        sort(edge+1,edge+1+m,cmp);
        /*
         for(int i = 1; i <=m; ++i){
         cout << edge[i].from<<" " << edge[i].to <<" "<<edge[i].w << endl;
         }
         */
        int cnt = 0;//判断是否连通,即边数 = 顶点数-1
        int ms = 1 << 30;
        int mae = -1;int mie = 1<<30;//初始化最大权值边,最小权值边
        bool flag = false;
        for(int i = 1; i <= m; ++i){
            mae = -1; mie = 1<<30;
            init(n);cnt = 0;
            for(int j = i; j <= m; ++j){
                Edge& u = edge[j];
                int x = find(u.from); int y = find(u.to);
                //cout << x <<" " << y << endl;
                if(x != y){
                    if(x > y) swap(x,y);
                    p[x] = y; cnt++; mae = max(mae,u.w); mie = min(mie,u.w);
                }
                //cout << cnt << endl;
                if(cnt == n-1){
                    ms = min(ms,mae - mie); flag = true; break;
                }
            }
        }
        if(flag)
            printf("%d\n",ms);
        else
            printf("-1\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值