@codeforces - 444A@ DZY Loves Physics

目录

  • @description@
  • @solution@
  • @accepted code@
  • @details@

@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 
#include 
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 场。。。

你可能感兴趣的:(@codeforces - 444A@ DZY Loves Physics)