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

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

``````#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;
}
``````