BZOJ-1266: [AHOI2006]上学路线route(最短路+最小割)

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <deque>
 
using namespace std ;
 
#define MAXV 1010
#define pb push_back
#define pf push_front
#define MAXM 150010
#define inf 0x7fffffff
#define MAXN 1010
 
struct network {
         
    struct edge {
        edge *next , *pair ;
        int t , f ;
    } *head[ MAXV ] ;
         
    void Add( int s , int t , int f ) {
        edge *p = new( edge ) ;
        p -> t = t , p -> f = f , p -> next = head[ s ] ;
        head[ s ] = p ;
    }
         
    void AddEdge( int s , int t , int f ) {
        Add( s , t , f ) , Add( t , s , 0 ) ;
        head[ s ] -> pair = head[ t ] , head[ t ] -> pair = head[ s ] ;
    }
         
    int S , T ;
         
    network(  ) {
        memset( head , 0 , sizeof( head ) ) ;
    }
         
    int h[ MAXV ] , gap[ MAXV ] ;
    edge *d[ MAXV ] ;
         
    int sap( int v , int flow ) {
        if ( v == T ) return flow ;
        int rec = 0 ;
        for ( edge *p = d[ v ] ; p ; p = p -> next ) if ( p -> f && h[ v ] == h[ p -> t ] + 1 ) {
            int ret = sap( p -> t , min( flow - rec , p -> f ) ) ;
            p -> f -= ret , p -> pair -> f += ret , d[ v ] = p ;
            if ( ( rec += ret ) == flow ) return flow ;
        }
        if ( ! ( -- gap[ h[ v ] ] ) ) h[ S ] = T ;
        gap[ ++ h[ v ] ] ++ , d[ v ] = head[ v ] ;
        return rec ;
    }
         
    int maxflow(  ) {
        int flow = 0 ;
        memset( h , 0 , sizeof( h ) ) ;
        memset( gap , 0 , sizeof( gap ) ) ;
        for ( int i = 0 ; i ++ < T ; ) d[ i ] = head[ i ] ;
        gap[ S ] = T ;
        while ( h[ S ] < T ) flow += sap( S , inf ) ;
        return flow ;
    }
         
} net ;
 
struct graph {
     
    struct edge {
        edge *next ;
        int t , d , c ;
    } *head[ MAXN ] ;
     
    int n ;
     
    graph(  ) {
        memset( head , 0 , sizeof( head ) ) ;
    }
     
    void Add( int s , int t , int d ) {
        edge *p = new( edge ) ;
        p -> t = t , p -> d = d , p -> next = head[ s ] ;
        head[ s ] = p ;
    }
     
    void AddEdge( int s , int t , int d ) {
        Add( s , t , d ) , Add( t , s , d ) ;
    }
     
    deque < int > q ;
    int dist[ MAXN ] ;
    bool f[ MAXN ] ;
     
    void spfa( int S ) {
        memset( f , false , sizeof( f ) ) ;
        q.clear(  ) ;
        for ( int i = 0 ; i ++ < n ; ) dist[ i ] = inf ;
        q.pf( S ) , dist[ S ] = 0 , f[ S ] = true ;
        while ( ! q.empty(  ) ) {
            int v = q.front(  ) ; q.pop_front(  ) , f[ v ] = false ;
            for ( edge *p = head[ v ] ; p ; p = p -> next ) {
                if ( dist[ p -> t ] > dist[ v ] + p -> d ) {
                    dist[ p -> t ] = dist[ v ] + p -> d ;
                    if ( ! f[ p -> t ] ) {
                        f[ p -> t ] = true ;
                        if ( ! q.empty(  ) && dist[ q.front(  ) ] > dist[ p -> t ] ) {
                            q.pf( p -> t ) ;
                        } else q.pb( p -> t ) ;
                    }
                }
            }
        }
    }
     
} g ;
 
int e[ MAXM ][ 4 ] , n , m ;
 
int main(  ) {
    scanf( "%d%d" , &n , &m ) ;
    g.n = n ;
    for ( int i = 0 ; i ++ < m ; ) {
        scanf( "%d%d%d%d" , &e[ i ][ 0 ] , &e[ i ][ 1 ] , &e[ i ][ 2 ] , &e[ i ][ 3 ] ) ;
        g.AddEdge( e[ i ][ 0 ] , e[ i ][ 1 ] , e[ i ][ 2 ] ) ;
    }
    g.spfa( 1 ) ;
    printf( "%d\n" , g.dist[ n ] ) ;
    net.S = 1 , net.T = n ;
    for ( int i = 0 ; i ++ < m ; ) {
        if ( g.dist[ e[ i ][ 1 ] ] == g.dist[ e[ i ][ 0 ] ] + e[ i ][ 2 ] ) {
            net.AddEdge( e[ i ][ 0 ] , e[ i ][ 1 ] , e[ i ][ 3 ] ) ;
        }
        if ( g.dist[ e[ i ][ 0 ] ] == g.dist[ e[ i ][ 1 ] ] + e[ i ][ 2 ] ) {
            net.AddEdge( e[ i ][ 1 ] , e[ i ][ 0 ] , e[ i ][ 3 ] ) ;
        }
    }
    printf( "%d\n" , net.maxflow(  ) ) ;
    return 0 ;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值