(生成树)CSU - 1845 Sensor network

题意:

有一个n个点m条边的图,每条边有个权值,现在要求此图所有生成树中最大权值和最小权值的差(暂且称为极差)的最小值。


 

分析:

如果暴力所有生成树复杂度是O(m^2)必然T,所以需要优化。

参考Kruskal算法,把边按权值从小到大排序,一条边一条边的加入,如果发现有环,说明这个环,可以进行优化,使接下来的生成树极差更小(加入的更大),这步优化就是删除这个环里最小的边。

这样,只需要在加入新的边之前,判断图中新边两点是否已经连通,并且返回权值最小的边。

然后删除最小边,加入新的边。

一旦当前图中边数==总顶点个数-1,就说明这是一颗生成树,更新一波最小值。

 

这个复杂度是O(n*m),官方题解说用并查集增删边可以使复杂度为O(mlogn)。

其实我一开始想的就是用并查集,用find可以飞速判断是否成环。

如果不进行路径压缩,貌似跟普通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也参与一下比较。

posted @ 2017-03-25 17:16  tak_fate  阅读(249)  评论(0编辑  收藏  举报