BZOJ-1486: [HNOI2009]最小圈(二分判定+DFS查负权圈)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1486

二分判定最小平均值,如果我们枚举一个端点mid,我们对所有边权减去mid,如果存在负权圈,那么就说明存在比枚举值更小的平均值,反之不存在,然后二分即可。

代码:

#include 

#include 

#include 

 

using namespace std ;

 

#define esp 0.0000000001

#define MAXN 3010

 

const double inf = double( 0x7fffffff ) * double( 0x7fffffff ) ;

 

struct edge {

    edge *next ;

    int t ;

    double d ;

    edge(  ) {

        next = NULL ;

    }

} *head[ MAXN ] ;

 

int n , m ;

 

void AddEdge( int s , int t , double d ) {

    edge *p = new( edge ) ;

    p -> t = t , p -> d = d , p -> next = head[ s ] ;

    head[ s ] = p ;

}

 

int cnt[ MAXN ] ;

double dist[ MAXN ] ;

bool f[ MAXN ] , flag , vis[ MAXN ] ;

 

void dfs( int v ) {

    f[ v ] = true ;

    for ( edge *p = head[ v ] ; p ; p = p -> next ) {

        if ( dist[ p -> t ] > dist[ v ] + p -> d ) {

            if ( ! f[ p -> t ] ) {

                dist[ p -> t ] = dist[ v ] + p -> d ;

                dfs( p -> t ) ;

            } else flag = true ;

            if ( flag ) break ;

        }

    }

    f[ v ] = false ;

}

 

bool check(  ) {

    memset( f , false , sizeof( f ) ) ;

    for ( int i = 0 ; i ++ < n ; ) dist[ i ] = 0 ;

    flag = false ;

    for ( int i = 0 ; i ++ < n ; ) {

        dfs( i ) ; if ( flag ) return false ;

    }

    return true ;

}

 

int main(  ) {

    memset( head , 0 , sizeof( head ) ) ;

    double l = inf , r = - inf ;

    scanf( "%d%d" , &n , &m ) ;

    while ( m -- ) {

        int s , t ; double d ; scanf( "%d%d%lf" , &s , &t , &d ) ;

        l = min( l , d ) , r = max( r , d ) ;

        AddEdge( s , t , d ) ;

    }

    while ( r - l > esp ) {

        double mid = ( l + r ) / 2.0 ;

        for ( int i = 0 ; i ++ < n ; ) {

            for ( edge *p = head[ i ] ; p ; p = p -> next ) {

                p -> d -= mid ;

            }

        }

        if ( check(  ) ) l = mid ; else r = mid ;

        for ( int i = 0 ; i ++ < n ; ) {

            for ( edge *p = head[ i ] ; p ; p = p -> next ) {

                p -> d += mid ;

            }

        }

    }

    printf( "%.8f\n" , l ) ;

    return 0 ;

}

你可能感兴趣的:(BZOJ-1486: [HNOI2009]最小圈(二分判定+DFS查负权圈))