1. 程式人生 > >(極差最小生成樹)POJ 3522 - Slim Span

(極差最小生成樹)POJ 3522 - Slim Span

給定 ans operator 維護 無向圖 ostream bre opera max

題意:

給定一張無向圖,求出一個最長邊減最短邊最小的生成樹。

分析:

這題之前做過一模一樣的(應該是。。。),跑kruskal算法,維護一個subset,一旦出現了環,就刪除這條環上最輕的邊,不斷更新subset,subset中存當前生成樹的邊,一旦邊的個數m=點數n-1,就更新ans。

這個復雜度是O(m*n)。但是在這裏樣例都過不去,應該是寫搓了。。。魯棒性不夠。

還有一個解法是用動態樹link-cut-tree,可以再把復雜度降成O(m*logn)。但是我還不會。。

這題因為點的數量只有100個,直接暴力就行了。

暴力枚舉限制最小的邊,計算最小生成樹即可。

代碼:

 1
#include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <vector> 6 7 8 using namespace std; 9 10 const int inf = 0x3f3f3f3f; 11 const int maxn = 110; 12 13 int n, m; 14 int par[maxn]; 15 16 struct Edge {
17 int u, v, c; 18 bool operator<(const Edge &a)const { 19 return c < a.c; 20 } 21 Edge(int _u, int _v, int _c) { 22 u = _u, v = _v, c = _c; 23 } 24 }; 25 26 vector<Edge> edge; 27 28 int findx(int x) { 29 if(par[x] == x)return x;
30 else return par[x] = findx(par[x]); 31 } 32 33 void init() { 34 for(int i = 1; i <= n; i++) { 35 par[i] = i; 36 } 37 } 38 39 int main() { 40 while(~scanf("%d%d", &n, &m)) { 41 if(n == 0 && m == 0)break; 42 edge.clear(); 43 for(int i = 0; i < m; i++) { 44 int u, v, c; 45 scanf("%d%d%d", &u, &v, &c); 46 edge.push_back(Edge(u, v, c)); 47 } 48 sort(edge.begin(), edge.end()); 49 int ans = inf; 50 for(int i = 0; i <= m - n + 1; i++) { 51 init(); 52 int cnt = 0; 53 for(int j = i; j < m; j++) { 54 int t1 = findx(edge[j].u); 55 int t2 = findx(edge[j].v); 56 if(t1 != t2) { 57 par[t1] = t2; 58 cnt++; 59 } 60 if(cnt == n - 1) { 61 ans = min(ans, edge[j].c - edge[i].c); 62 break; 63 } 64 } 65 } 66 if(ans == inf)puts("-1"); 67 else printf("%d\n", ans); 68 } 69 return 0; 70 71 }

(極差最小生成樹)POJ 3522 - Slim Span