@codeforces - 444A@ DZY Loves Physics
@description@
给定一个 n 点 m 边的图,边有边权,点有点权。
找到一个连通的诱导子图(选中的点之间的边必须选,选中的边的端点必须选),使得这个子图的密度最大。
密度的定义为:如果边权和为 0,则密度 = 0;否则密度 = 点权和 / 边权和。
Input
第一行两个空格隔开的整数 n (1 ≤ n ≤ 500), m (1 ≤ m ≤ n*(n-1)/2)。
第二行 n 个空格隔开的整数 xi (1 ≤ xi ≤ 10^6),表示每个点的点权。
接下来 m 行,每行三个空格隔开的整数 ai, bi, ci (1 ≤ ai < bi ≤ n; 1 ≤ ci ≤ 10^3),描述了一条边。保证没有重边。
Output
输出一个实数表示答案。
Examples
Input
1 0
1
Output
0.000000000000000
Input
2 1
1 2
1 2 1
Output
3.000000000000000
@solution@
一看还以为是什么 01 分数规划 + 最大闭合权子图。。。
注意这个密度的定义很像平均值,而平均值最值还有另一个解法:min{a, b} <= a 与 b 的平均值 <= max{a, b}。
也就是说最优情况一定只取单个元素。
套个这个题上面,大胆猜测只取一条边最优。
感性证明一下。假如一条边对应的端点点权和为 ai,边权为 bi。
首先有 max{ai/bi, aj/bj} >= (ai + aj)/(bi + bj),可以反证。
那么一个包含多条边的图,对应的密度 (∑ai - delta)/∑bi <= ∑ai/∑bi <= max{ai/bi}。其中 delta 是算重复的点权。
@accepted code@
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 500;
double x[MAXN + 5], ans;
int main() {
int n, m; scanf("%d%d", &n, &m);
for(int i=1;i<=n;i++) scanf("%lf", &x[i]);
for(int i=1;i<=m;i++) {
int a, b; double c; scanf("%d%d%lf", &a, &b, &c);
ans = max(ans, (x[a] + x[b]) / c);
}
printf("%.9f\n", ans);
}
@details@
偶尔切一切小清新的结论题还是挺开心的~
话说这个比赛场次。。。第 444 场。。。