uvalive3887
给定一个带权的无向图,求得一棵最小生成树,是的树中的最大边权-最小边权的差值最小
分析:当确定一个最小边时(其他的边的权值都比他大),那么之后按照kruskal算法得到的最小生成树,
此时得到的最小生成树的最大权值也肯定是最小的,因为是kruskal是按照贪心来选边的。
所以只要不断的枚举是哪条边作为最小边,然后生成最小生成树,记录所有差值中最小的一个就是答案。
时间复杂度是O(m*m*logm)
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <algorithm> 5 #include <iostream> 6 #include <queue> 7 #include <stack> 8 #include <vector> 9 #include <map> 10 #include <set> 11 #include <string> 12 #include <math.h> 13 using namespace std; 14 #pragma warning(disable:4996) 15 #pragma comment(linker, "/STACK:1024000000,1024000000") 16 typedef long long LL; 17 const int INF = 1<<30; 18 /* 19 最大边的权值减去最小边的权值 要最小的生成树, 20 即树的边权尽可能相近 21 22 枚举最小边的权值,然后生成生成树 , 然后计算权值之差, 取取最小的那一个 23 时间复杂度是m * m * logm , 24 25 26 因为生成树是 27 */ 28 const int N = 350 + 10; 29 struct Edge 30 { 31 int u, v, dis; 32 bool operator<(const Edge&rhs) 33 { 34 return dis < rhs.dis; 35 } 36 }g[N*N]; 37 int fa[N]; 38 int find(int x) 39 { 40 if (x == fa[x]) 41 return x; 42 return fa[x] = find(fa[x]); 43 } 44 int kruskal(int n, int j ,int m) 45 { 46 for (int i = 0; i <= n; ++i) 47 { 48 fa[i] = i; 49 } 50 int cnt = 0, ret = 0; 51 for (int i = j; i < m; ++i) 52 { 53 int fx = find(g[i].u); 54 int fy = find(g[i].v); 55 if (fx != fy) 56 { 57 fa[fx] = fy; 58 if (cnt == 0) 59 ret = g[i].dis; 60 if (cnt != 0 && g[i].dis - ret > ans) 61 return -1; 62 cnt++; 63 if (cnt == n - 1) 64 ret = g[i].dis - ret; 65 } 66 } 67 if (cnt == n - 1) 68 return ret; 69 return -1; 70 } 71 72 73 int main() 74 { 75 //freopen("d:/in.txt", "r", stdin); 76 int n, m; 77 while (scanf("%d",&n),n) 78 { 79 scanf("%d", &m); 80 for (int i = 0; i < m; ++i) 81 scanf("%d%d%d", &g[i].u, &g[i].v, &g[i].dis); 82 sort(g, g + m); 83 int ans = kruskal(n, 0 ,m); 84 if (ans == -1) 85 puts("-1"); 86 else 87 { 88 for (int i = 1; i < m; ++i) 89 { 90 int ret = kruskal(n, i, m); 91 if (m - i < n - 1) 92 break; 93 if (ret != -1) 94 ans = min(ans, ret); 95 } 96 printf("%d\n", ans); 97 } 98 } 99 return 0; 100 }
时间: 2024-10-13 23:47:51