(生成樹)CSU - 1845 Sensor network

題意:ios

有一個n個點m條邊的圖,每條邊有個權值,如今要求此圖全部生成樹中最大權值和最小權值的差(暫且稱爲極差)的最小值。算法


 

分析:優化

若是暴力全部生成樹複雜度是O(m^2)必然T,因此須要優化。spa

參考Kruskal算法,把邊按權值從小到大排序,一條邊一條邊的加入,若是發現有環,說明這個環,能夠進行優化,使接下來的生成樹極差更小(加入的更大),這步優化就是刪除這個環裏最小的邊。code

這樣,只須要在加入新的邊以前,判斷圖中新邊兩點是否已經連通,而且返回權值最小的邊。blog

而後刪除最小邊,加入新的邊。排序

一旦當前圖中邊數==總頂點個數-1,就說明這是一顆生成樹,更新一波最小值。ci

 

這個複雜度是O(n*m),官方題解說用並查集增刪邊能夠使複雜度爲O(mlogn)。string

其實我一開始想的就是用並查集,用find能夠飛速判斷是否成環。it

若是不進行路徑壓縮,貌似跟普通dfs判連通沒啥區別了。

若是進行了路徑壓縮,若是刪除的是與根節點直接相連的邊,感受就BOOM了。

因此,不會~


 

代碼:

  1 #include <set>
  2 #include <map>
  3 #include <list>
  4 #include <cmath>
  5 #include <queue>
  6 #include <stack>
  7 #include <vector>
  8 #include <bitset>
  9 #include <string>
 10 #include <cctype>
 11 #include <cstdio>
 12 #include <cstring>
 13 #include <cstdlib>
 14 #include <iostream>
 15 #include <algorithm>
 16 // #include <unordered_map>
 17 
 18 using namespace std;
 19 
 20 typedef long long ll;
 21 typedef unsigned long long ull;
 22 typedef pair<int, int> pii;
 23 typedef pair<ull, ull> puu;
 24 
 25 #define inf (0x3f3f3f3f)
 26 #define lnf (0x3f3f3f3f3f3f3f3f)
 27 #define eps (1e-9)
 28 #define fi first
 29 #define se second
 30 
 31 bool sgn(double a, string select, double b) {
 32     if(select == "==")return fabs(a - b) < eps;
 33     if(select == "!=")return fabs(a - b) > eps;
 34     if(select == "<")return a - b < -eps;
 35     if(select == "<=")return a - b < eps;
 36     if(select == ">")return a - b > eps;
 37     if(select == ">=")return a - b > -eps;
 38 }
 39 
 40 
 41 //--------------------------
 42 
 43 const ll mod = 1000000007;
 44 const int maxn = 10010;
 45 
 46 struct Edge {
 47     int u, v;
 48     int val;
 49 
 50     bool operator<(const Edge &a)const {
 51         if(val != a.val)return val < a.val;
 52         else if(u != a.u)return u < a.u;
 53         else return v < a.v;
 54     }
 55 
 56     bool operator==(const Edge &a)const {
 57         if(u == a.u && v == a.v && val == a.val)return true;
 58         if(u == a.v && v == a.u && val == a.val)return true;
 59         return false;
 60     }
 61 
 62 
 63 } edge[150010];
 64 
 65 
 66 set<int> G[400];
 67 bool vis[400];
 68 int vs[400][400];
 69 
 70 set<Edge> subset;
 71 Edge lightest;
 72 
 73 
 74 bool circy(int u, int v) {
 75     if(u == v)return true;
 76     vis[u] = true;
 77     bool res = false;
 78     for(set<int>::iterator it = G[u].begin(); it != G[u].end(); it++) {
 79         if(!vis[*it] && circy(*it, v)) {
 80             if(lightest.val > vs[u][*it]) {
 81                 lightest.u = u;
 82                 lightest.v = *it;
 83                 lightest.val = vs[u][*it];
 84             }
 85             res = true;
 86             break;
 87         }
 88     }
 89     return res;
 90 }
 91 
 92 void solve() {
 93     int n, m;
 94     while(scanf("%d%d", &n, &m) && n) {
 95         for(int i = 0; i < n; i++) {
 96             G[i].clear();
 97         }
 98         subset.clear();
 99         for(int i = 0; i < m; i++) {
100             scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].val);
101             if(edge[i].u > edge[i].v)swap(edge[i].u, edge[i].v);
102             vs[edge[i].u][edge[i].v] = vs[edge[i].v][edge[i].u] = edge[i].val;
103         }
104         sort(edge, edge + m);
105         int ans = inf;
106         for(int i = 0; i < m; i++) {
107             lightest = edge[i];
108             memset(vis, 0, sizeof(vis));
109             subset.insert(edge[i]);
110             if(circy(edge[i].u, edge[i].v)) {
111                 if(lightest.u > lightest.v)swap(lightest.u, lightest.v);
112                 G[lightest.u].erase(lightest.v);
113                 G[lightest.v].erase(lightest.u);
114                 subset.erase(lightest);
115             }
116             G[edge[i].u].insert(edge[i].v);
117             G[edge[i].v].insert(edge[i].u);
118             if(subset.size() == n - 1) {
119                 ans = min(ans, (subset.rbegin()->val - subset.begin()->val));
120             }
121         }
122         printf("%d\n", ans );
123     }
124 
125 
126 }
127 
128 int main() {
129 
130 #ifndef ONLINE_JUDGE
131     freopen("1.in", "r", stdin);
132     freopen("1.out", "w", stdout);
133 #endif
134     // iostream::sync_with_stdio(false);
135     solve();
136     return 0;
137 }

後記:

在用set的時候出現一堆坑,也說明本身對STL容器知識的匱乏。

set的去重是直接與operator<相關的。

若是你的operator<只寫了比較val,那麼當val相等,可是u和v不等的時候,這條新的邊依然會被過濾掉。

因此要讓u和v也參與一下比較。

相關文章
相關標籤/搜索