梦后楼台高锁,酒醒帘幕低垂
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 Output4 4
3 4 1
2 3 2
1 2 4
2 4 3
1
Source
2017 UESTC Training for Graph Theory
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