https://www.luogu.org/recordnew/show/6125570
思路就是巧妙的枚举所有的生成树,取最优值
首先按照边权排序
找出第一颗最小生成树(l, r),其中l表示最小边的编号,r表示最大边的编号
然后从r+1号边开始倒序枚举各边,求出第二颗最小生成树(当然也可能不存在)(l_2, r_2), r_2 = r + 1.
这样的话就省去了多条最小边的枚举
比如若从2 -- l_2-1中任选一条边作为最小边开始查询最大生成树,那么最大边一定为r_2
这样的话差值不会比(l_2, r_2)这颗生成树更优,所以就简化了算法
然后从将l_2+1号边作为最小边开始枚举,依次进行下去
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int N = 5e4 + 10; #define gc getchar() int fa[N]; struct Node{int u, v, w;} G[N << 2]; int n, m, Answer = 999999999; inline int read() { int x = 0; char c = gc; while(c < '0' || c > '9') c = gc; while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc; return x; } inline bool cmp(Node a, Node b) {return a.w < b.w;} int get_fa(int x) {return fa[x] == x ? x : fa[x] = get_fa(fa[x]);} void Printf() {cout << Answer; exit(0);} void dfs(int start, int how) { for(int i = 1; i <= n; i ++) fa[i] = i; int tot = 0, Maxn = 0, Minn = 0, Nxt; if(how % 2) {//cong xiao dao da for(int i = start; i <= m; i ++) { int fa_u = get_fa(G[i].u), fa_v = get_fa(G[i].v); if(fa_u != fa_v) { fa[fa_u] = fa_v; tot ++; if(tot == n - 1) {Maxn = G[i].w; Nxt = i; break;} } } if(!Maxn) Printf(); Answer = min(Answer, Maxn - G[start].w); } else { for(int i = start; i >= 1; i --) { int fa_u = get_fa(G[i].u), fa_v = get_fa(G[i].v); if(fa_u != fa_v) { fa[fa_u] = fa_v; tot ++; if(tot == n - 1) {Minn = G[i].w; Nxt = i; break; } } } if(!Minn) Printf(); Answer = min(Answer, G[start].w - Minn); } dfs(Nxt + 1, how + 1); } int main() { n = read(); m = read(); for(int i = 1; i <= m; i ++) G[i].u = read(), G[i].v = read(), G[i].w = read(); sort(G + 1, G + m + 1, cmp); dfs(1, 1); return 0; }