UESTC 1636 梦后楼台高锁,酒醒帘幕低垂 最小生成树Kruskal算法的扩展

梦后楼台高锁,酒醒帘幕低垂

Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)


Submit  Status
给你一个有n个点和m条边的无向连通图,每条边都有一个权值w.
我们定义,对于一条路径,它的Charm value为该路径上所有边的权值的最大值与最小值的差.
询问从1到n的所有路径的Charm value的最小值.


Input

第一行有两个整数n,m(1≤n≤200,n−1≤m≤1000),表示该图有n个点和m条边.
接下来m行,每行三个整数u,v,w(1≤u,v≤n,1≤w≤1000000),表示点u和点v之间有一条权值为w的边.


Output

输出一个数,即从1到n的所有路径的Charm value的最小值.


Sample input and output

Sample Input Sample Output
4 4
3 4 1
2 3 2
1 2 4
2 4 3

1


Source

2017 UESTC Training for Graph Theory

UESTC 1636 梦后楼台高锁,酒醒帘幕低垂


My Solution

题意:给出一个有n个点和m条边的无向连通图,每条边都有一个权值w.
定义,对于一条路径,它的Charm value为该路径上所有边的权值的最大值与最小值的差.
询问从1到n的所有路径的Charm value的最小值.


最小生成树Kruskal算法的扩展
首先把边按照边权排序,然后对于每个i,向后枚举,并把边加入连通块,当1和n属于同一个连通块时刷新
ans,并接着枚举下一个i。
时间复杂度 O(mlogm)
空间复杂度 O(m)


#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 2e2 + 8;

struct edge{
    int u, v, w;
    edge(int u = 0, int v = 0, int w = 0) : u(u), v(v), w(w) {}
}e[5*MAXN];
inline bool cmp(const edge &a, const edge &b){
    return a.w < b.w;
}

int fa[MAXN], _rank[MAXN];
inline void init(int n){
    for(int i = 0; i <= n; i++){
        fa[i] = i;
        _rank[i] = 0;
    }
}
inline int _find(int u){
    return fa[u] = fa[u] == u ? u : _find(fa[u]);
}
inline void _merge(int u, int v){
    int x = _find(u), y = _find(v);
    if(x == y) return;
    if(_rank[x] < _rank[y]){
        fa[x] = y;
    }
    else{
        fa[y] = x;
        if(_rank[x] == _rank[y]) _rank[x]++;
    }
}

int main()
{
    #ifdef LOCAL
    freopen("a.txt", "r", stdin);
    //freopen("a.out", "w", stdout);
    int T = 1;
    while(T--){
    #endif // LOCAL
    //ios::sync_with_stdio(false); cin.tie(0);

    int n, m, i, j, u, v, w, ans = 1e9 + 8;
    //cin >> n;
    scanf("%d%d", &n, &m);
    for(i = 0; i < m; i++){
        scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
    }
    sort(e, e + m, cmp);
    for(i = 0; i < m; i++){
        init(n);
        for(j = i; j < m; j++){
            _merge(e[j].u, e[j].v);
            if(_find(1) == _find(n)){
                ans = min(ans, e[j].w - e[i].w);
                break;
            }
        }
    }

    printf("%d\n", ans);

    #ifdef LOCAL
    cout << endl;
    }
    #endif // LOCAL
    return 0;
}



  Thank you!

                                                                                                                                             ------from ProLights

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值