zoukankan      html  css  js  c++  java
  • hdu 4081 次小生成树

    http://acm.hdu.edu.cn/showproblem.php?pid=4081

    我就不说题意了,为了使A/B最大,就应该是B越小,故可以先求出n个点的最小生成树。因此,可以枚举每一条边,假设最小生成树的值是B, 而枚举的那条边长度是edge[i][j],  如果这一条边已经是属于最小生成树上的,那么最终式子的值是A/(B-edge[i][j])。如果这一条不属于最小生成树上的, 那么添加上这条边,就会有n条边,那么就会使得有了一个,为了使得它还是一个生成树,就要删掉环上的一棵树。 为了让生成树尽量少,那么就要删掉除了加入的那条边以外,权值最大的那条路径。 假设删除的那个边的权值是Max[i][j], 那么就是A/(B-Max[i][j]).

    这题的关键也在于怎样求出次小生成树;

    先用prim求出最小生成树T.在prim的同时,用一个矩阵max[u][v] 记录 在T中连结任意两点u,v的唯一的路中权值最大的那条边的权值.这是很容易做到的,因为prim是每次增加一个结点s, 而设已经标号了的结点集合为W, 则W中所有的结点到s的路中的最大权值的边就是当前加入的这条边.

    View Code
     1 #include<iostream>
     2 #include<cstring>
     3 #include<cmath>
     4 const int N=1010;
     5 const double inf=1e14;
     6 using namespace std;
     7 
     8 struct Point{
     9     int x,y,z;
    10 }point[N];
    11 
    12 int n;
    13 double edge[N][N];
    14 int nearvex[N];//保存前驱
    15 double  lowcost[N]; 
    16 double sum;
    17 
    18 int used[N][N];
    19 int visited[N];
    20 double  Max[N][N];//用来保存最小生成树中两点之间的权值最大的边
    21 
    22 
    23 void prim(int v0){
    24     sum=0;
    25     memset(used,0,sizeof(used));
    26     memset(visited,0,sizeof(visited));
    27     memset(Max,0,sizeof(Max));
    28     for(int i=1;i<=n;i++){
    29         lowcost[i]=edge[v0][i];
    30         nearvex[i]=v0;
    31     }
    32     visited[v0]=1;
    33     for(int i=1;i<n;i++){
    34         double min=inf;
    35         int v=-1;
    36         for(int j=1;j<=n;j++){
    37             if(!visited[j]&&lowcost[j]<min){
    38                 v=j,min=lowcost[j];
    39             }
    40         }
    41         if(v!=-1){
    42             sum+=lowcost[v];
    43             used[v][nearvex[v]]=used[nearvex[v]][v]=1;//标记这条边已经是最小使用过//
    44             visited[v]=1;
    45             for(int k=1;k<=n;k++){
    46                 if(visited[k]&&k!=v){
    47                     //对于那些已经加入最小生成树的边,只要每次更新所有点到新加入的点之间的边权值最大值即可
    48                     Max[v][k]=Max[k][v]=(Max[k][nearvex[v]]>lowcost[v]?Max[k][nearvex[v]]:lowcost[v]);
    49                 }
    50                 if(!visited[k]&&edge[v][k]<lowcost[k]){
    51                     lowcost[k]=edge[v][k];
    52                     nearvex[k]=v;
    53                 }
    54             }
    55         }
    56     }
    57 }
    58 
    59 
    60 int main(){
    61     int t;
    62     scanf("%d",&t);
    63     while(t--){
    64         scanf("%d",&n);
    65         for(int i=1;i<=n;i++){
    66             scanf("%d%d%d",&point[i].x,&point[i].y,&point[i].z);
    67         }
    68         for(int i=1;i<=n;i++){
    69             edge[i][i]=0;
    70             for(int j=i+1;j<=n;j++){
    71                 double dis=sqrt(pow((point[i].x-point[j].x)*1.0,2)+pow((point[i].y-point[j].y)*1.0,2));
    72                 edge[i][j]=edge[j][i]=dis;
    73             }
    74         }
    75         prim(1);
    76         double r=-1;
    77         for(int i=1;i<=n;i++){
    78             for(int j=1;j<=n;j++)if(i!=j){
    79                 if(used[i][j]){
    80                     r=(r>(point[i].z+point[j].z)*1.0/(sum-edge[i][j])?r:(point[i].z+point[j].z)*1.0/(sum-edge[i][j]));
    81                 }else if(!used[i][j]){
    82                     r=(r>(point[i].z+point[j].z)*1.0/(sum-Max[i][j])?r:(point[i].z+point[j].z)*1.0/(sum-Max[i][j]));
    83                 }
    84             }
    85         }
    86         printf("%.2lf\n",r);
    87     }
    88     return 0;
    89 }
  • 相关阅读:
    面象对象设计原则之七:合成复用原则(Composition/Aggregate Reuse Principle, CARP)
    GRASP软件设计的模式和原则
    UniDAC 安装教程
    Delphi 实现检测线程类TThread是否结束
    DELPHI线程例子-FC
    Delphi Stringlist Delimiter如何区分TAB和空格
    DBGrid1
    UTF-8 delphi 函数
    未测试 Delphi读写UTF-8、Unicode格式文本文件
    mysql + unidac 使用事务例子
  • 原文地址:https://www.cnblogs.com/wally/p/2892194.html
Copyright © 2011-2022 走看看