zoukankan      html  css  js  c++  java
  • 2011年 北京区域赛A题 Qin Shi Huang's National Road System // hdu 4081 Qin Shi Huang's National Road System 最优比率生成树

    /*
    
    2011年北京区域赛A题
    Qin Shi Huang's National Road System
    
    题目:
        秦始皇想要修公路,使得这n座城市可以互达,题目给出n所城市的二维坐标以及每座城
        市的价值,现在有人可以免费帮助秦始皇修理任意一条公路,现在要想使得比率A/B最大,
        A表示这条公路所在的两座城市的价值,B表示所有的公路长度(不包括这条公路的长度)。
    
    分析:
        想要比率最大,所以A要尽可能大,B尽可能小。要使B尽可能小的话,可以先求的最小生
        成树,然后枚举在最小生成树上的每条边,删除该边后得到的两个点集中分别找到最大价值
        的点(城市),然后更新答案。时间复杂度为O(n^2)。而找两个集合中的点时,我们可以
        通过dfs求得,具体实现请看代码
    
    */
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <cmath>
    
    using namespace std;
    
    const int X = 1002;
    #define INF 1e12
    
    struct node
    {
        int x,y,w;
    }p[X];
    
    int n;
    double map[X][X];
    double dis[X],total,ans;
    bool use[X];
    int pre[X];     //记录点i的前趋节点
    
    double dist(int x1,int y1,int x2,int y2)    //距离
    {
        return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    }
    
    void prim() //求最小生成树
    {
        memset(pre,0,sizeof(pre));
        total = 0;
        memset(use,false,sizeof(use));
        for(int i=1;i<=n;i++)
            dis[i] = INF;
        dis[1] = 0;
        int k;
        double MIN;
        for(int i=0;i<n;i++)
        {
            MIN = INF;
            for(int j=1;j<=n;j++)
                if(!use[j]&&dis[j]<MIN)
                    MIN = dis[k = j];
            use[k] = true;
            total += MIN;
            for(int j=1;j<=n;j++)
                if(!use[j]&&dis[j]>map[k][j])
                    dis[j] = map[k][j],pre[j] = k;
        }
    }
    
    void dfs(int i) //dfs,通过对他的后趋点进行深搜,找到同一集合中所有的点
    {
        use[i] = true;
        for(int j=1;j<=n;j++)
            if(!use[j]&&pre[j]==i)
                dfs(j);
    }
    
    void solve()
    {
        double temp;
        ans = 0;
        int a,b;
        for(int i=1;i<=n;i++)   //枚举每条边
        {
            if(pre[i]==0)
                continue;
            temp = total-map[i][pre[i]];    //删除边i,pre[i]
            memset(use,false,sizeof(use));
            dfs(i);
            a = b = 0;
            for(int j=1;j<=n;j++)
            {
                if(use[j]&&j!=pre[i])   //与pre[i]同一集合中的点,找到最大的价值城市
                    a = max(a,p[j].w);
                else if(!use[j]&&j!=i)    //与i同一集合中的点。。。
                    b = max(b,p[j].w);
            }
            ans = max(ans,(a+b)/temp);
        }
        printf("%.2lf\n",ans);
    }
    int main()
    {
        freopen("sum.in","r",stdin);
        freopen("sum.out","w",stdout);
        int t;
        cin>>t;
        while(t--)
        {
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            {
                scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].w);
                for(int j=i;j>=1;j--)   //预处理出所有点与点之间的距离
                    map[i][j] = map[j][i] = dist(p[i].x,p[i].y,p[j].x,p[j].y);
            }
            prim();
            solve();
        }
        return 0;
    }
  • 相关阅读:
    Codeforces Round #650 (Div. 3)
    C. Count Triangles
    A National Pandemic (思维 + 树链剖分模版)
    扫描线专题
    扫描线模版
    莫队模版
    JS设计模式 -- 4种创建型模式
    滑动窗口的最大值 -- 单调队列
    JS链表实现栈和队列
    js数组扁平化的几种实现方式
  • 原文地址:https://www.cnblogs.com/yejinru/p/2547746.html
Copyright © 2011-2022 走看看