Qin Shi Huang's National Road System(次小生成树)

                                                                                       


                                                                                                 Qin Shi Huang's National Road System


题目链接:Click Here~

题目重述:

    题目说秦始皇要修路,把N个城市用N-1条边连通。且他希望花费最小,但是这时候有一个多管闲事的道士出来说他有魔法可以帮助秦始皇变成一条路,但是只能变出一条。但是,两个人对修路的法案存在歧义,道士希望修路可以给更多的百姓带来福利,而秦始皇希望修路要尽量使花费小。最后,秦始皇拿出了一个公式A/B,A表示两个城市的人数,B表示出了用魔法变出来的路外,最短的总距离。现在要你求出A/B的最大值。


思路分析:

   从题目可以看出是一个此小生成树问题,但是也有人有DP AC了。具体思路就看网上别人的解释吧。


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;

const int N = 1e3 + 5;
int n,m;
double path[N][N],G[N][N];
bool used[N][N],hash[N];
struct Point
{
  double x,y,cost;
}p[N];

double Dist(Point a,Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

double Prim()
{
    int pre[N];
    double sum = 0,mincost[N];
    memset(hash,0,sizeof(hash));
    memset(used,0,sizeof(used));
    memset(path,0,sizeof(path));
    hash[1] = 1;
    for(int i = 1;i <= n;++i){
       mincost[i] = G[1][i];
       pre[i] = 1;
    }
    for(int i = 1;i < n;++i)
    {
        int u = -1;
        for(int j = 1;j <= n;++j)if(!hash[j]){
           if(u == -1||mincost[j] < mincost[u])
             u = j;
        }
        hash[u] = 1;
        used[u][pre[u]] = used[pre[u]][u] = 1;                          //判断两点之间是否在生成树中
        sum += G[pre[u]][u];
        for(int j = 1;j <= n;++j)
        {
            if(hash[j]&&u != j){
               path[j][u] = path[u][j] = max(mincost[u],path[j][pre[u]]);  //生成树中的最大权值
//               path[j][u] = path[u][j] = mincost[u];
            }
            if(!hash[j]){
               if(mincost[j] > G[u][j]){
                  mincost[j] = G[u][j];
                  pre[j] = u;
               }
            }
        }
    }
    return sum;
}
int main()
{
    int T; 
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i = 1;i <= n;++i){
           scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].cost);
        }
        memset(G,0,sizeof(G));
        for(int i = 1;i <= n;++i)
          for(int j = i+1;j <= n;++j){
             G[i][j] = G[j][i] = Dist(p[i],p[j]);
          }
       double mincost = Prim();
       double ratio = -1;
       for(int i = 1;i <= n;++i)
         for(int j = 1;j <= n;++j)
           printf("path[%d][%d] = %lf\n",i,j,path[i][j]);
       for(int i = 1;i <= n;++i)
         for(int j = i+1;j <= n;++j){
             if(used[i][j]){
                 ratio = max(ratio,(p[i].cost+p[j].cost)/(mincost-G[i][j]));
             }else
             {    //删除生成树中的最大的一条边,生成一个类此小生成树(因为,不是严格的此小生成树)
                 ratio = max(ratio,(p[i].cost+p[j].cost)/(mincost-path[i][j]));   
             }
         }
       printf("%.2lf\n",ratio);
    }
    return 0;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值