[HDU 4081] Qin Shi Huang's National Road System 最小樹


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

題意:輸入一個 n , 表示有 n 個 城市,然后輸入x, y, v, 分別表示地 i 個城市的坐標和人口數, 現在要修路n-1 條路,讓每個城市都連通。可以用魔法變出一條路。求這條路的兩端點的 總人數 / (包含這條邊的最小生成樹的總權值) 最大值。

思路:用次小生成樹的思路求解,先求出最小生成樹,然后枚舉每一條邊。

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int inf = (1 << 31) - 1;

struct Point{
    double x, y;
};

int n;
int val[1005];
Point point[1005];  //坐標
bool intr[1005][1005]; //i - k 這條邊是否在最小生成樹中
double mapn[1005][1005]; //i - k 之間的距離
double maxn[1005][1005]; // 最小生成樹中 i - k 的路徑中最長的邊

int pre[1005];  //前驅
bool vis[1005];  //標記數組
double dis[1005];  //到前驅的距離

double length(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 rt)  //最小生成樹
{
    memset(vis, false, sizeof(vis));
    memset(intr, false, sizeof(intr));
    double res = 0;
    vis[rt] =  true;
    for(int i = 1; i <= n; i++){
        dis[i] = mapn[rt][i];
        pre[i] = 1;
    }
    for(int k = 1; k < n; k++)
    {
        int mid = -1;
        for(int i = 1; i <= n; i++) //找最小的邊
        {
            if(!vis[i] && (mid == -1 || dis[i] < dis[mid])){
                mid = i;
            }
        }
        res += dis[mid];
        vis[mid] = true;
        intr[mid][pre[mid]] = intr[pre[mid]][mid] = true;  //標記邊在最小生成樹中
        for(int i = 1; i <= n; i++){
            if(!vis[i] && dis[i] > mapn[mid][i])  //更新點到前驅的距離
            {
                dis[i] = mapn[mid][i];
                pre[i] = mid;
            }
            if(vis[i] && i != mid)  //mid 到每個點 的路徑中最大的距離
            {
                double x = maxn[pre[mid]][i];
                double y = mapn[mid][pre[mid]];
                maxn[mid][i] = maxn[i][mid] = x > y ? x : y;
            }
        }
    }
    return res;
}

int main()
{
    int Test;
    scanf("%d", &Test);
    while(Test--){
        scanf("%d", &n);
        for(int i = 1; i <= n; i++){
            scanf("%lf%lf%d", &point[i].x, &point[i].y, &val[i]);
        }
        for(int i = 1; i <= n; i++){
            for(int k = i; k <= n; k++){
                maxn[i][k] = maxn[k][i] = (i == k ? 0 : inf);
                mapn[i][k] = mapn[k][i] = length(point[i], point[k]);
            }
        }
        double sum = Prim(1);
        double resl = -1;
        for(int i = 1; i <= n; i++) //枚舉每條邊
        {
            for(int k = i+1; k <=n; k++) 
            {
                if(intr[i][k]){  //如果這條邊在最小樹中
                    resl = max(resl, (val[i]+val[k])/(sum-mapn[i][k]));
                }
                else{  //如果不在最小樹中
                    resl = max(resl, (val[i]+val[k])/(sum-maxn[i][k]));  //刪除路徑中最長的邊
                }
            }
        }
        printf("%.2lf\n", resl);
    }
    return 0;
}

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com