zoukankan      html  css  js  c++  java
  • UVALive 5713 Qin Shi Huang's National Road System(次小生成树)

    题意:对于已知的网络构建道路,使城市两两之间能够互相到达。其中一条道路是可以免费修建的,问需要修建的总长度B与免费修建的道路所连接的两城市的人口之和A的比值A/B最大是多少。

    因为是求A/B的最大值,自然A越大,B越小越好。B的最小值是可以用最小生成树算法求解的,但是,由于免费修建一条道路,使得B值<最小生成树的权值和cnt。

    于是,就要考虑究竟选择哪条边作为免费修建?只考虑生成树上的边还是全部边都要考虑?仔细想一下,就会发现任何一条边都存在这样的可能性。而A/B的值同时收A、B的影响,即B可以稍微大一点,只要A增大的倍数更大,那么A/B就会出现一个更优解。

    至此,选择枚举每一条边(u,v)作为可能免费修建的边。当然,若它在最小生成树上,那么B==cnt-边权;若它不在最小生成树上,那么加上该条边相当于在树形结构上构造了一个环,那么减去环上任何一条边(当然不能是新加的这条边),又构成一棵树。当删除的是原树上u,v两点唯一路径上权值最大的一条边时,这棵树就是对应于所加的边(u,v)“次小生成树”(这里的次小不是真正的次小)。为什么一定是当前次小呢?由kruskal算法可知,这是通过贪心构造出的一棵树,新加上的边必然是环上的最大值(否则就不会是最小生成树了),而不在环上的边可以保证最小,所以通过如上构造,得到了一棵确定选择边(u,v)后的最小生成树,也是原图的一颗次小生成树(究竟是不是真的是次小,要比较完全部的“次小生成树”才能得到,并且注意次小生成树不唯一)。

    用prim算法实现,记录(u,v)两两之间的路径上的最大值:每次记录即将加入生成树的点v与已加入的点之间的最大值,f[v]=max{f[u],w(u,v)},u是v的父亲。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cmath>
     4 #include<vector>
     5 #include<algorithm>
     6 #define clr(a,m) memset(a,m,sizeof(a))
     7 #define rep(i,a,b) for(int i=a;i<=b;i++)
     8 using namespace std;
     9 
    10 const int MAXN=1111;
    11 const double INF =1e9;
    12 
    13 struct Point{
    14     int c;
    15     double x,y;
    16 }p[MAXN];
    17 
    18 double mp[MAXN][MAXN],f[MAXN][MAXN];
    19 
    20 double d[MAXN];
    21 int vis[MAXN],fa[MAXN];
    22 
    23 double prim(int n)
    24 {
    25     vector<int>q;
    26     double cnt=0;
    27 
    28     clr(vis,0);
    29     rep(i,1,n)
    30         d[i]=INF;
    31     d[1]=0;
    32     fa[1]=1;
    33     rep(i,1,n){
    34         int x;
    35         double m=INF;
    36         rep(y,1,n)
    37             if(!vis[y]&&d[y]<m)
    38                 m=d[x=y];
    39         vis[x]=true;
    40         cnt+=mp[fa[x]][x];
    41 
    42         int sz=q.size();
    43         rep(j,0,sz-1){
    44             f[q[j]][x]=f[x][q[j]]=max(f[q[j]][fa[x]],mp[fa[x]][x]);
    45         }
    46         q.push_back(x);
    47 
    48         rep(y,1,n)
    49             if(!vis[y]&&mp[x][y]<d[y]){
    50                 d[y]=mp[x][y];
    51                 fa[y]=x;
    52             }
    53     }
    54     return cnt;
    55 }
    56 
    57 void print(int n,double cnt)
    58 {
    59     double m=0;
    60     rep(i,1,n)
    61         rep(j,i+1,n){
    62             double s=cnt-f[i][j];
    63             double t=p[i].c+p[j].c;
    64             m=max(m,t/s);
    65         }
    66     printf("%.2f
    ",m);
    67 }
    68 
    69 int main()
    70 {
    71     int T,n;
    72     scanf("%d",&T);
    73     while(T--)
    74     {
    75         scanf("%d",&n);
    76         rep(i,1,n)
    77             scanf("%lf%lf%d",&p[i].x,&p[i].y,&p[i].c);
    78         rep(i,1,n){
    79             mp[i][i]=0;
    80             rep(j,i+1,n)
    81                 mp[i][j]=mp[j][i]=sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y));
    82         }
    83         double cnt=prim(n);
    84         print(n,cnt);
    85     }
    86     return 0;
    87 }
    View Code
  • 相关阅读:
    ES6基础
    RegExp正则表达式基础
    JavaScript基础之--- 手写 bind 方法的实现
    JavaScript基础之--- 手写 apply方法 的实现
    JavaScript基础之--- 手写 call 的实现
    JavaScript基础之--- 手写instanceof 的实现
    git系列之---工作中项目的常用git操作
    git系列之---将本地的项目添加到码云仓库
    git系列之---码云gitee 添加SHH公钥
    TCP的三次握手过程
  • 原文地址:https://www.cnblogs.com/zstu-abc/p/3280495.html
Copyright © 2011-2022 走看看