• (生成树)CSU


    题意:

    有一个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
    ", 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也参与一下比较。

  • 相关阅读:
    Three.js实现3D地图实例分享
    three.js中让模型自动居中的代码如下:
    three.js obj转js的详细步骤 convert_obj_three.py的用法
    three.js
    Web三维编程入门总结之三:3D碰撞检测初探
    Web三维编程入门总结之二:面向对象的基础Web3D框架
    Web三维编程入门总结之一:WebGL与Threejs入门知识
    主流浏览器css兼容问题的总结
    Three.js三维模型几何体旋转、缩放和平移
    从3dMax导出供threeJS使用的带动作模型与加载
  • 原文地址:https://www.cnblogs.com/tak-fate/p/6617708.html
Copyright © 2020-2023  润新知