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

来源:互联网 发布:数据迁移服务 编辑:程序博客网 时间:2024/06/05 20:00

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;}
0 0
原创粉丝点击