zoukankan      html  css  js  c++  java
  • [HNOI2009]最小圈 题解

    题目大意

    给你一个有向图,求出图中环的平均值的最小值

    环的平均值定义:环中所有的边权和/环中点数量

    思路

    看到使平均值最大或最小,可以考虑分数规划

    分数规划用于解决一些要让平均值最大或最小的问题

    具体就是二分答案(K)

    (frac{x_1+x_2+x_3+dots+x_n}{n}ge kLeftrightarrow (x_1-k)+(x_2-k)+(x_3-k)+dots+(x_n-k)ge 0)

    很明显,这题完全满足这个分数规划的性质。

    故我们枚举一个(k),把每条边的边权减去(k),再用(SPFA)判负环就可以了

    具体细节见代码

    #include <bits/stdc++.h>
    using namespace std ;
    const int MAXN = 10000 + 5 ;
    struct Node {
        int next , to ;
        double w ;
    } edge[ MAXN ] ;
    int head[ MAXN ] , cnt ;
    int n , m ;
    double d[ MAXN ] ;
    bool vis[ MAXN ] ;
    inline int read () {
        int tot = 0 , f = 1 ; char c = getchar () ;
        while ( c < '0' || c > '9' ) { if ( c == '-' ) f = -1 ; c = getchar () ; }
        while ( c >= '0' && c <= '9' ) { tot = tot * 10 + c - '0' ; c = getchar () ; }
        return tot * f ;
    }
    inline void add ( int x , int y , double z ) {
        edge[ ++ cnt ].next = head[ x ] ;
        edge[ cnt ].to = y ;
        edge[ cnt ].w = z ;
        head[ x ] = cnt ;
    }
    inline bool spfa ( int u , double t ) {
        vis[ u ] = 1 ;
        for ( int i = head[ u ] ; i ; i = edge[ i ].next ) {
            int v = edge[ i ].to ;
            if ( d[ u ] + edge[ i ].w - t < d[ v ] ) {
                d[ v ] = d[ u ] + edge[ i ].w - t ;
                if ( vis[ v ] || spfa ( v , t ) ) return 1 ; //判负环
            }
        }
        vis[ u ] = 0 ;
        return 0 ;
    }
    inline bool check ( double t ) {
        for ( int i = 1 ; i <= n ; i ++ ) d[ i ] = 0 ;
        memset ( vis , 0 , sizeof ( vis ) ) ;
        for ( int i = 1 ; i <= n ; i ++ ) if ( spfa ( i , t ) ) return 1 ; //每个点都要作为起点来判一遍
        return 0 ;
    }
    signed main () {
        n = read () ; m = read () ;
        for ( int i = 1 ; i <= m ; i ++ ) {
            int x = read () , y = read () ;
            double z ; cin >> z ;
            add ( x , y , z ) ;
        }
        double l = -1e7 , r = 1e7 ;
        while ( r - l > 1e-12 ) { // 二分答案
            double mid = ( l + r ) / 2 ;
            if ( check ( mid ) ) r = mid ;
            else l = mid ;
        }
        printf ( "%.8lf
    " , r ) ;
        return 0 ;
    }
    
  • 相关阅读:
    hibernate中的配置参数详解
    js 提示框
    Caused by: java.sql.SQLException: 数字溢出
    什么是Assembly(程序集)?
    我的邮箱
    hdu 3746(KMP的循环节问题)
    hdu 1176(一道简单的dp)
    hdu 1385(求出最短路并输出最短路径)
    hdu 1003(最大连续字串)
    hdu 4512(最长公共递增子序列加强版)
  • 原文地址:https://www.cnblogs.com/hulean/p/13469677.html
Copyright © 2011-2022 走看看