• UVAlive5713 Qin Shi Huang's National Road System【次小生成树】【DP】


    LINK1

    LINK2


    题目大意

    给你平面上的n个点

    每个点有一个权值

    让你求出一个生成树

    可以选择一条边不花费代价

    要最大化这条边两边端点的权值/剩下n-2条边的长度之和

    思路

    发现发现其实端点权值其实不太好处理

    那么我们就用最暴力的方式来枚举这样的一条边

    但是显然剩下的部分不能直接暴力最小生成树

    那么就直接在原图的最小生成树上面进行考虑

    加上一条边一定需要删除一条边

    这样的操作一定会删除两点对应生成树链上的最大边权

    所以可以预处理生成树上两点之间的最大边权

    这个可以用一个简单的树形dp来完成

    算法复杂度(n^2)也没问题

    也可以用主席树来标记永久化维护

    但是查询的时候会多一个log

    //Author: dream_maker
    #include<bits/stdc++.h>
    using namespace std;
    //----------------------------------------------
    typedef pair<int, int> pi;
    typedef long long ll;
    typedef double db;
    #define fi first
    #define se second
    #define fu(a, b, c) for (int a = b; a <= c; ++a)
    #define fd(a, b, c) for (int a = b; a >= c; --a)
    #define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
    const int INF_of_int = 1e9;
    const ll INF_of_ll = 1e18;
    template <typename T>
    void Read(T &x) {
      bool w = 1;x = 0;
      char c = getchar();
      while (!isdigit(c) && c != '-') c = getchar();
      if (c == '-') w = 0, c = getchar();
      while (isdigit(c)) {
        x = (x<<1) + (x<<3) + c -'0';
        c = getchar();
      }
      if (!w) x = -x;
    }
    template <typename T>
    void Write(T x) {
      if (x < 0) {
        putchar('-');
        x = -x;
      }
      if (x > 9) Write(x / 10);
      putchar(x % 10 + '0');
    }
    //----------------------------------------------
    const int M = 1e6 + 10;
    const int N = 1e3 + 10;
    db dis[N][N], f[N][N];
    pi pos[N];
    int n, m, p[N];
    
    db getpow(int x) {
      return (db)x * (db)x;
    }
    
    db getdis(pi x, pi y) {
      return sqrt(getpow(x.fi - y.fi) + getpow(x.se - y.se));
    }
    
    void getdis() {
      fu(i, 1, n) {
        fu(j, 1, n) {
          dis[i][j] = getdis(pos[i], pos[j]);
        }
      }
    }
    
    struct Edge {
      int u, v, nxt;
      bool operator < (const Edge b) const {
        return dis[u][v] < dis[b.u][b.v];
      }
    };
    struct Map {
      Edge E[M << 1];
      int head[N], tot, n;
      
      void init(int pn) {
        n = pn;
        fu(i, 1, n) head[i] = 0;
        tot = 0;
      }
    
      void addedge(int u, int v) {
        E[++tot] = (Edge) {u, v, head[u]};
        head[u] = tot;
      }
      
      void sortedge() {
        sort(E + 1, E + tot + 1);
      }
    } mp, mst;
    
    struct Union_Find {
      int fa[N];
      
      void init(int n) {
        fu(i, 1, n) fa[i] = i;
      }
      
      int Find(int x) {
        return x == fa[x] ? x : fa[x] = Find(fa[x]);
      }
      
      bool Merge(int x, int y) {
        int fax = Find(x), fay = Find(y);
        if (fax == fay) return 0;
        fa[fax] = fay;
        return 1;
      }
    } uf;
    
    db Kruskal() {
      uf.init(n);
      mst.init(n);
      int cnt = 0;
      db res = 0;
      fu(i, 1, mp.tot) {
        int u = mp.E[i].u, v = mp.E[i].v;
        if (uf.Merge(u, v)) {
          mst.addedge(u, v);
          mst.addedge(v, u);
          res += dis[u][v];
          if (++cnt == n - 1) break;
        }
      }
      return res;
    }
    
    bool mark[N];
    
    void dfs(int u, int fa) {
      mark[fa] = 1;
      if (fa) {
        fu(j, 1, n) if (u != j) {
          f[u][j] = f[j][u] = max(f[fa][j], dis[u][fa]);    
        }
      }
      for (int i = mst.head[u]; i; i = mst.E[i].nxt) {
        int v = mst.E[i].v;
        if (v != fa) dfs(v, u);
      }
    }
    
    void solve() {
      Read(n);
      fu(i, 1, n)
        Read(pos[i].fi), Read(pos[i].se), Read(p[i]);
      getdis();
      mp.init(n);
      fu(i, 1, n)
        fu(j, 1, i - 1)
          mp.addedge(i, j);
      mp.sortedge();
      db tmp = Kruskal();
      fu(i, 1, n) mark[i] = 0;
      dfs(1, 0);
      db ans = 0;
      fu(i, 1, n)
        fu(j, 1, i - 1)
          ans = max(ans, db(p[i] + p[j]) / (tmp - f[i][j]));
      printf("%.2lf
    ", ans);
    }
    
    int main() {
    #ifdef dream_maker
      freopen("input.txt", "r", stdin);
    #endif
      int T; Read(T);
      while (T--) solve();
      return 0;
    }
    
  • 相关阅读:
    全选、反选和不选
    树状图
    年月日选择器
    细谈HTML5
    再谈HTML
    FlashFXP 破解代码
    文件上传示例
    PHP聊天室框架
    JS判断是否来自手机移动端的访问,并跳转
    JQUERY知识总结
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9903706.html
Copyright © 2020-2023  润新知