题目:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3714
题目大意:n个平面上的城市要修建道路,每个城市有人,使他们连通。有一个人他能用法术造出任意一条道路。现在给你这 n 个点的二维坐标,设法术造的路两端的城市人口和为 A,B为人工造的道路长度之和,A 要尽量大,B要尽量小,让你求出最大的 A/B。
解题思路:和次小生成树的做法一样。先求出最小生成树,然后 dfs 遍历求出max_cost(u,v) 数组,即 u 到 v 最小生成树上唯一路径中边权的最大值。复杂度O(n^2)。然后枚举用法术搞哪一条道路,本来一棵树 n-1 条边,加上一条后,就变成了 n 条边,有一个环。把其中新加进去的这条边的两端的 max_cost ,换成0,tot_val 直接减掉就好。然后再求出最大值就行了。
代码如下:
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
const int EPS = 1e-8;
const int MAXN = 1111;
struct City
{
int x,y,val;
void read()
{
scanf("%d%d%d",&x,&y,&val);
}
} city[MAXN];
struct Edge
{
int s,t;
double val;
Edge(){}
Edge(int a,int b,double c)
{
s = a;t = b;val = c;
}
bool operator < (const Edge& tmp) const
{
return val < tmp.val;
}
} edge[MAXN*MAXN];
struct MST
{
int n;
int edge_count;
void add_edge(int s,int t,double val)
{
edge[edge_count++] = Edge(s,t,val);
}
int fa[MAXN];
int find_fa(int x)
{
if(fa[x] == x) return x;
else return fa[x] = find_fa(fa[x]);
}
vector< pair<int,double> > G[MAXN];
double tot_val;
void krus()
{
sort(edge,edge+edge_count);
for(int i = 0;i < n;i++)
fa[i] = i,G[i].clear();
tot_val = 0;
for(int i = 0;i < edge_count;i++)
{
int a = edge[i].s;
int b = edge[i].t;
int fx = find_fa(a);
int fy = find_fa(b);
if(fx == fy) continue;
fa[fx] = fy;
tot_val += edge[i].val;
G[a].push_back(make_pair(b,edge[i].val));
G[b].push_back(make_pair(a,edge[i].val));
}
}
double max_cost[MAXN][MAXN];
vector<int> vec;
void dfs(int u,int fa)
{
vec.push_back(u);
for(int i = 0;i < G[u].size();i++)
{
int v = G[u][i].first;
double val = G[u][i].second;
if(v != fa)
{
for(int i = 0;i < vec.size();i++)
max_cost[vec[i]][v] = max_cost[v][vec[i]] = max(val,max_cost[vec[i]][u]);
dfs(v,u);
}
}
}
void init(int n)
{
this->n = n;
edge_count = 0;
}
void solve()
{
krus();
memset(max_cost,0,sizeof(max_cost));
vec.clear();
dfs(0,-1);
}
} mst;
double get_ans()
{
double ans = 0;
for(int i = 0;i < mst.edge_count;i++)
{
int s = edge[i].s;
int t = edge[i].t;
double tmp = mst.tot_val-mst.max_cost[s][t];
ans = max(ans,(city[s].val+city[t].val+0.0)/tmp);
}
return ans;
}
double dis(int a,int b)
{
return sqrt((city[a].x-city[b].x)*(city[a].x-city[b].x)+(city[a].y-city[b].y)*(city[a].y-city[b].y));
}
int main()
{
int _;
scanf("%d",&_);
while(_--)
{
int n;
scanf("%d",&n);
for(int i = 0;i < n;i++)
city[i].read();
mst.init(n);
for(int i = 0;i < n;i++)
for(int j = i+1;j < n;j++)
mst.add_edge(i,j,dis(i,j));
mst.solve();
double ans = get_ans();
printf("%.2f\n",ans);
}
return 0;
}