• @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 场。。。

  • 相关阅读:
    [ APIO 2015 ] 雅加达的摩天楼
    「POI2011 R1」Conspiracy
    「COCI2016/2017 Contest #2」Bruza
    「THUWC 2017」随机二分图
    「HAOI2015」按位或
    Topcoder Srm 726 Div1 Hard
    「LOJ6482」LJJ爱数数
    「2017 山东一轮集训 Day4」基因
    「Codechef April Lunchtime 2015」Palindromeness
    「UOJ207」共价大爷游长沙
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/11852054.html
Copyright © 2020-2023  润新知