法术只能修一条路,不妨枚举它两端的城市u和v。如果可以再O(1)的时间内算出“在原图中删除u-v后的最小生成树权值”,就可以在O(n^2)时间内解决本题了。
先求出最小生成树,在枚举边u-v后删除最先生成树u和v之间唯一路径上的最大权maxcost [u][v]。只需在预处理时用O(n^2)时间算出maxcost数组,问题就得到了解决。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <string>
#include <cmath>
using namespace std;
typedef long long LL;
typedef unsigned long long LLU;
const int maxn=1111;
int p[maxn], pre[maxn], n, fa[maxn];
double maxcost[maxn][maxn], g[maxn][maxn], cost_sum;
vector<int> G[maxn];
struct Point
{
double x, y;
double P;
} point[maxn];
struct Edge
{
int u, v;
double dist;
Edge(int u, int v, double dist):u(u), v(v), dist(dist) {}
bool operator < (const Edge & a)const
{
return dist<a.dist;
}
};
vector<Edge> edges;
void init()
{
for(int i=0; i<=n; i++)
{
p[i]=i;
G[i].clear();
}
edges.clear();
}
int find(int x)
{
return x == p[x] ? x : p[x]=find(p[x]);
}
double distance_(int i, int j)
{
return sqrt((point[i].x-point[j].x)*(point[i].x-point[j].x)+(point[i].y-point[j].y)*(point[i].y-point[j].y));
}
void MST()
{
int cnt=0;
cost_sum=0;
for(int i=0; i<edges.size() && cnt<n-1; i++)
{
int x=find(edges[i].u), y=find(edges[i].v);
if(x!=y)
{
cnt++;
p[x]=y;
G[edges[i].u].push_back(edges[i].v);
G[edges[i].v].push_back(edges[i].u);
cost_sum+=edges[i].dist;
}
}
}
void dfs_build_tree(int u, int deep, int p)
{
fa[u]=p;
pre[u]=deep;
for(int i=0; i<G[u].size(); i++)
{
int v=G[u][i];
if(!pre[v])
dfs_build_tree(v, deep+1, u);
}
}
double cost(int i, int j)
{
if(maxcost[i][j]>=0)
return maxcost[i][j];
if(i==j)
return maxcost[i][j]=maxcost[j][i]=0;
if(pre[i]>pre[j])
swap(i, j);
return maxcost[i][j]=maxcost[j][i]=max(cost(i, fa[j]), g[j][fa[j]]);
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
init();
for(int i=0; i<n; i++)
scanf("%lf%lf%lf", &point[i].x, &point[i].y, &point[i].P);
for(int i=0; i<n; i++)
for(int j=i+1; j<n; j++)
{
g[i][j]=g[j][i]=distance_(i, j);
edges.push_back(Edge(i, j, g[i][j]));
}
sort(edges.begin(), edges.end());
MST();
memset(pre, 0, sizeof(pre));
dfs_build_tree(0, 1, -1);
memset(maxcost, -1, sizeof(maxcost));
for(int i=0; i<n; i++)
for(int j=i+1; j<n; j++)
maxcost[i][j]=maxcost[j][i]=cost(i, j);
double ans=0;
for(int i=0; i<n; i++)
for(int j=i+1; j<n; j++)
ans=max(ans, (point[i].P+point[j].P)/(cost_sum-maxcost[i][j]));
printf("%.2lf\n", ans);
}
return 0;
}