原题链接
- 题意:遍历每个非关键边,预处理出来两个 (MST) 中的点到最近公共祖先的最长的边的距离,然后就是 (frac{cnt}{sum - Max_{i,j}}) 枚举 (i,j) 即可,简直就和求最小生成树的过程一模一样。
- 代码:
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
const int N = 1111;
const int M = 2 * N * N;
int cnt = 0;
double sum = 0;
int h[N], to[M], ne[M], idx;
double W[M];
int dep[N];
int f[N][20];
double g[N][20];
void add(int u, int v ,double w) {
ne[idx] =h[u], to[idx] = v, W[idx] =w, h[u] = idx++;
}
void dfs(int u, int fa) {
if (fa == -1)dep[u] = 1;
else dep[u] = dep[fa] + 1;
for (int i = 1; i <= 13; i ++) {
f[u][i] = f[f[u][i-1]][i-1];
g[u][i] = max(g[u][i-1],g[f[u][i-1]][i-1]);
}
for (int i = h[u]; i!= -1; i = ne[i]) {
int v = to[i];
if (dep[v] == 0) {
f[v][0] = u;
g[v][0] = W[i];
dfs(v, u);
}
}
}
struct node {
double x, y;
int cnt;
}p[N];
struct edge {
int u, v;double w;
int cnt;
}e[M];
bool cmp(edge a, edge b){return a.w < b.w;}
int fa[N];
int Find(int x){return fa[x] == x?x:fa[x] = Find(fa[x]);}
double dis(node a, node b) {
return sqrt((a.x- b.x)*(a.x-b.x) + (a.y - b.y) * (a.y - b.y));
}
void un(int i) {
int fx = Find(e[i].u);
int fy = Find(e[i].v);
if (fx == fy)return;
fa[fx] = fy;
add(e[i].u, e[i].v, e[i].w);
add(e[i].v, e[i].u, e[i].w);
sum += e[i].w;
}
double lca(int u, int v) {
if (dep[u] < dep[v])swap(u, v);
double ret = -1;
for (int i = 14; i >= 0; i--) {
if (dep[f[u][i]] >= dep[v]) {
ret = max(ret, g[u][i]);
u = f[u][i];
}
}
if (u == v)return ret;
for (int i = 14; i >= 0; i--) {
if (f[u][i] != f[v][i]) {
ret = max(ret, max(g[u][i], g[v][i]));
u = f[u][i], v = f[v][i];
}
}
ret = max(ret, max(g[u][0], g[v][0]));
return ret;
}
void solve() {
int n;scanf("%d", &n);
for (int i = 1; i <= n; i ++) {
scanf("%lf%lf%d", &p[i].x, &p[i].y,&p[i].cnt);
fa[i] = i;
}
int m = 0;cnt = 0;
sum = 0;
double ans = -1;
memset(h, -1, sizeof h);idx = 0;
memset(dep, 0, sizeof dep);
for (int i = 1; i <= n; i ++) {
for (int j = i + 1; j <= n; j ++) {
e[++m] = {i, j, dis(p[i], p[j])};
}
}
sort(e + 1, e + 1 + m, cmp);
for (int i = 1; i <= m; i ++) {
un(i);
}
dfs(1, -1);
for (int i = 1; i <= n; i ++) {
for (int j = i + 1; j <=n; j ++) {
ans = max(ans,(double)( p[i].cnt + p[j].cnt*1.0 )/(sum - lca(i, j) ) );
}
}
printf("%.2lf
", ans);
}
signed main() {
int t;scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}