HDU 4081 Qin Shi Huang's National Road System
这个题也是类似求比值最优的问题,应该不能简单贪心求解,就只好枚举喽。
A
是某条边上两点的点权之和,B
是在上述两点已经连通的情况下图的最小生成树的值。想让A/B
最大。
枚举每条边,也就枚举了每种可能的A
,有两种情况:
- 该边 是 mst上的边,在这两点已经确定的情况下,B
的最小值就是mst的值减去该边的权值。(借助kruskal
算法可以理解)
- 该边 不是 mst上的边,此时mst加上该边一定会形成有且只有一个环,环上除此边以外任意一条边的权值只会小于等于该边的权值,而且环上去除任意一条边之后就是生成树。所以在这种情况下,B
的最小值就是mst的值减去该环上属于mst的边(除此边之外)中的最大权值。
可以设这条不在mst中的边的起点和终点为i
,j
,那么只要求出在mst中i
到j
路径上(有且只有一条路径)的最大边权max_edge[i][j]
就可以了。用prim
顺便求这个会比较方便。(在松弛循环中可以根据前驱来更新,且prim
要确定入选mst边时也会根据前驱)
求“次小生成树”也会用到max_edge[i][j]
。
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <cmath>
using namespace std;
const int INF = 1e9;
const int MAXN = 1e3 + 2;
int N;
struct Point
{
int x, y, pop;
}city[MAXN];
double g[MAXN][MAXN];
bool active[MAXN][MAXN];
double max_edge[MAXN][MAXN];
bool vis[MAXN];
double d[MAXN];
int pre[MAXN];
double ans;
double B;
void init()
{
fill(vis, vis + N, 0);
fill(d, d + N, INF);
memset(active, 0, sizeof active);
ans = -1;
}
double getDistance(int i, int j)
{
return sqrt((double)(pow(city[i].x - city[j].x, 2) + pow(city[i].y - city[j].y, 2)));
}
void prim()
{
B = 0;
d[0] = 0;
for (int i = 0; i < N; i++)
{
double mind = INF;
int u = -1;
for (int j = 0; j < N; j++)
{
if (!vis[j] && d[j] < mind)
{
mind = d[j];
u = j;
}
}
B += mind;
vis[u] = 1;
if (u) active[u][pre[u]] = active[pre[u]][u] = 1;
for (int j = 0; j < N; j++)
{
if (vis[j] && j != u) ////
{
if (pre[u] == j) max_edge[u][j] = max_edge[j][u] = g[u][j];
else max_edge[u][j] = max_edge[j][u] = max(max_edge[pre[u]][j], g[u][pre[u]]);
}
else if (!vis[j] && g[u][j] < d[j])
{
d[j] = g[u][j];
pre[j] = u;
}
}
}
}
int main()
{
int T;
scanf("%d", &T);
for (; T--;)
{
scanf("%d", &N);
init();
for (int i = 0; i < N; i++)
scanf("%d%d%d", &city[i].x, &city[i].y, &city[i].pop);
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
if (i != j) g[i][j] = g[j][i] = getDistance(i, j);
prim(); // 其重要任务是计算数组max_edge[][]
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
if (i != j)
{
if (active[i][j])
ans = max(ans, ((double)(city[i].pop + city[j].pop)) / (B - g[i][j]));
else ans = max(ans, ((double)(city[i].pop + city[j].pop)) / (B - max_edge[i][j]));
}
}
}
printf("%.2f\n", ans);
}
return 0;
}