• uvaLive5713 次小生成树


    uvaLive5713

    修建道路使得n个点任意两点之间都可以连通,每个点有都有一定的人口,现在可以免费修一条道路,

    A是免费修的道路两端结点的人口之和, B的其它不是免费修道路的长度的总和

    要求的是A/B的最短值。

    B其实就是最小生成树删除一条边只有的权值之和B。 只要我们知道生成树上任意两点之间的最长边,那么只要在这两点之间修一条边,

    然后删除最长边,它还是一棵树。 而已这时候的权值之和是B-maxCost[u][v]

    那么 答案就是min{p[u][v] / (B-maxCost[u][v])} , 枚举u,v的时间复杂度是O(n*n)。

    至于得到maxCost[u][v] 只要在得到最小生成树之后,一遍dfs就可以求出

    求解的方法是:当访问一个新节点时,计算所有已经访问过的结点到这个结点的最小权值

    max[u][x] = maxCost[x][u] = max(maxCost[x][fa],edge(u,fa))

    u是当前访问的结点,fa是u的父亲, x是所有已经访问过的结点。

    (其实就是两个嵌套的循环,只不过是在树上循环罢了)

    总的时间复杂度是n*n + e*loge     常数没有计算进去。

    n*n和eloge 最大时都是1000多w, 3s的时间,足够了

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <stdlib.h>
      4 #include <algorithm>
      5 #include <iostream>
      6 #include <queue>
      7 #include <stack>
      8 #include <vector>
      9 #include <map>
     10 #include <set>
     11 #include <string>
     12 #include <math.h>
     13 using namespace std;
     14 #pragma warning(disable:4996)
     15 #pragma comment(linker, "/STACK:1024000000,1024000000")
     16 typedef long long LL;                   
     17 const int INF = 1<<30;
     18 /*
     19 
     20 */
     21 const int N = 1000 + 10;
     22 struct Edge
     23 {
     24     int form, to, p;
     25     double dist;
     26     bool operator<(const Edge&rhs)const
     27     {
     28         return dist < rhs.dist;
     29     }
     30 }a[N*N];
     31 int x[N], y[N], p[N];
     32 int father[N];
     33 double maxCost[N][N];
     34 int p2[N][N];
     35 vector<Edge> g[N];
     36 vector<int> st;
     37 int find(int x)
     38 {
     39     if (x == father[x])
     40         return x;
     41     return father[x] = find(father[x]);
     42 }
     43 double kruskal(int n)
     44 {
     45     double sum = 0;
     46     for (int i = 0; i < n; ++i)
     47     {
     48         int fx = find(a[i].form);
     49         int fy = find(a[i].to);
     50         if (fx != fy)
     51         {
     52             //记录生成树,用来等下dfs
     53             g[a[i].form].push_back(a[i]);
     54             swap(a[i].form, a[i].to);
     55             g[a[i].form].push_back(a[i]);
     56             sum += a[i].dist;
     57             father[fx] = fy;
     58         }
     59     }
     60     return sum;
     61 }
     62 
     63 /*
     64 这个dfs其实就是给定一棵树,然后求任意两点之间的最大边权, 因为是任意两点, 那么时间复杂度无疑就是O(n*n)
     65 */
     66 void dfs(int u, int fa, double dis)
     67 {
     68     if (fa!=-1)
     69     for (int i = 0; i < st.size(); ++i)
     70     {
     71         int x = st[i];
     72         maxCost[x][u] = maxCost[u][x] = max(maxCost[x][fa], dis);
     73     }
     74     st.push_back(u);
     75     for (int i = 0; i < g[u].size(); ++i)
     76     {
     77         int v = g[u][i].to;
     78         if (v == fa) continue;
     79         dfs(v, u, g[u][i].dist);
     80     }
     81 }
     82 int main()
     83 {
     84     int t, n, cnt;
     85     double B;
     86     scanf("%d", &t);
     87     while (t--)
     88     {
     89         scanf("%d", &n);
     90         cnt = 0;
     91         st.clear();
     92         for (int i = 0; i < n; ++i)
     93         {
     94             father[i] = i;
     95             g[i].clear();
     96             scanf("%d%d%d", &x[i], &y[i], &p[i]);
     97         }
     98         for (int i = 0; i < n; ++i)
     99         {
    100             for (int j = i + 1; j < n; ++j)
    101             {
    102                 p2[i][j] = p2[j][i] = p[i] + p[j];
    103                 //边集数组
    104                 a[cnt].form = i;
    105                 a[cnt].to = j;
    106                 a[cnt].p = p[i] + p[j];
    107                 a[cnt++].dist = sqrt((x[i] - x[j])*(x[i] - x[j]) + (y[i] - y[j])*(y[i] - y[j]));
    108             }
    109         }
    110         sort(a, a + cnt);
    111         B = kruskal(cnt);
    112         dfs(0, -1, 0);
    113         double ans = 0;
    114 
    115         //枚举在哪两个之间建免费的道路
    116         for (int i = 0; i < n; ++i)
    117             for (int j = i + 1; j < n; ++j)
    118                 ans = max(ans, p2[i][j] / (B - maxCost[i][j]));
    119         printf("%.2lf
    ", ans);
    120     }
    121     return 0;
    122 }
    View Code
  • 相关阅读:
    Winform中如何禁用最大化或最小化按钮
    联想笔记本白屏解决办法
    SqlSever查询当前数据库某个表的名称、列名称、列说明
    离线安装Microsoft SQL Server 2016时Microsoft R Open和Microsoft R Server的问题
    SqlSever查询当前数据库的所有表名及其描述
    Windows10系统C盘的ESD文件夹是什么?可以删除吗?
    飞秋截图的快捷键是什么?
    打开Word时报错:Cannot find the Word document template:WordToRqm.dot
    .Net Core 2.1 上传文件后保存在根目录下的文件夹中,但是通过网页链接访问不了
    Winform弹出确认窗口
  • 原文地址:https://www.cnblogs.com/justPassBy/p/4681092.html
Copyright © 2020-2023  润新知