@codeforces


@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
", ans);
}

@details@

偶尔切一切小清新的结论题还是挺开心的~
话说这个比赛场次。。。第 444 场。。。

原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/11852054.html