LOJ6011「網絡流 24 題 - 12」運輸問題 墜小費用墜大流 墜大費用墜大流

大家都很強, 可與之共勉 。

題意:
  W 公司有m 個倉庫和n 個零售商店。第i 個倉庫有ai 個單位的貨物;第j 個零售商店需要 bj 個單位的貨物。貨物供需平衡,即 i=1mai=j=1nbj 。從第 i 個倉庫運送每單位貨物到第j 個零售商店的費用爲cij ​ 。試設計一個將倉庫中所有貨物運送到零售商店的運輸方案,使總運輸費用最少。

  然而他要讓您輸出最小方案和最大方案。

題解:

  她都告訴你了流量平衡……直接就是費用流啊。(會不會給人一種硬點的感覺

  虛擬源點S ,和匯點T ,然後Sm 個倉庫,容量爲ai ,費用爲0 ,倉庫和零售店連容量爲+ ,費用爲cij 的邊,然後零售店連T ,容量爲bj ,費用爲0

  一遍最小費用最大流,一遍最大費用最大流。

  其實都可以轉化爲最小費用最大流,對於最大費用,費用變成相反數,就變成了求最小費用最大流,最後答案是相反數。

# include <bits/stdc++.h>

template < class T >  inline bool chkmax ( T& d, const T& x )  {  return d < x ? ( d = x ), 1 : 0 ;  }
template < class T >  inline bool chkmin ( T& d, const T& x )  {  return d > x ? ( d = x ), 1 : 0 ;  }

# define oo 0x3f3f3f3f

# define N 5010
# define M 16010

class  MinCostMaxFlow  {
    private :
        struct edge  {
            int to, nxt, w, cost ;
        } g [M << 1] ;

        int S, T ;
        int head [N], dis [N], pre [N], ecnt ;

        inline bool spfa ( int S, int T )  {
            static std :: bitset < N > inq ;
            static std :: deque < int > Q ;
            inq.reset ( ) ; Q.clear ( ) ;
            memset ( pre, 0, sizeof ( int ) * ( T + 1 ) ) ;
            memset ( dis, 0x3f, sizeof ( int ) * ( T + 1 ) ) ;
            Q.push_front ( S ) ;
            inq [S] = 1 ;
            dis [S] = 0 ;
            while ( ! Q.empty ( ) )  {
                int u = Q.front ( ) ; Q.pop_front ( ) ;
                inq [u] = 0 ;
                for ( int i = head [u] ; i ; i = g [i].nxt )  {
                    int& v = g [i].to ;
                    if ( g [i].w && chkmin ( dis [v], dis [u] + g [i].cost ) )  {
                        pre [v] = i ;
                        if ( ! inq [v] )  {
                            ( Q.empty ( ) || dis [v] < dis [Q.front ( )] ) ? Q.push_front ( v ) : Q.push_back ( v ) ;
                            inq [v] = 1 ;
                        }
                    }
                }
            }
            return ( bool ) pre [T] ;
        }
    public :
        MinCostMaxFlow ( )  {  ecnt = 1 ; memset ( head, 0, sizeof head ) ;  }

        inline void add_edge ( int u, int v, int w, int cost )  {
            g [++ ecnt] = ( edge )  {  v, head [u], w, cost } ; head [u] = ecnt ;
            g [++ ecnt] = ( edge )  {  u, head [v], 0, -cost } ; head [v] = ecnt ;
        }

        std :: pair < int, int > mcmf ( int S, int T )  {
            this -> S = S, this -> T = T ;
            int flow = 0, cost = 0, x ;
            while ( spfa ( S, T ) )  {
                x = oo ;
                for ( int i = pre [T] ; i ; i = pre [g [i ^ 1].to] )  chkmin ( x, g [i].w ) ;
                for ( int i = pre [T] ; i ; i = pre [g [i ^ 1].to] )  {
                    g [i].w -= x, g [i ^ 1].w += x ;
                    cost += x * g [i].cost ;
                }

                flow += x ;
            }
            return std :: make_pair ( flow, cost ) ;
        }
} Lazer1 ;

class  MaxCostMaxFlow  {
    private :
        struct edge  {
            int to, nxt, w, cost ;
        } g [M << 1] ;

        int S, T ;
        int head [N], dis [N], pre [N], ecnt ;

        inline bool spfa ( int S, int T )  {
            static std :: bitset < N > inq ;
            static std :: deque < int > Q ;
            inq.reset ( ) ; Q.clear ( ) ;
            memset ( pre, 0, sizeof ( int ) * ( T + 1 ) ) ;
            memset ( dis, -1, sizeof ( int ) * ( T + 1 ) ) ;
            Q.push_front ( S ) ;
            inq [S] = 1 ;
            dis [S] = 0x3f3f3f3f ; // big enough !!!
            while ( ! Q.empty ( ) )  {
                int u = Q.front ( ) ; Q.pop_front ( ) ;
                inq [u] = 0 ;
                for ( int i = head [u] ; i ; i = g [i].nxt )  {
                    int& v = g [i].to ;
                    if ( g [i].w && chkmax ( dis [v], dis [u] + g [i].cost ) )  {
                        pre [v] = i ;
                        if ( ! inq [v] )  {
                            ( Q.empty ( ) || dis [v] > dis [Q.front ( )] ) ? Q.push_front ( v ) : Q.push_back ( v ) ;
                            inq [v] = 1 ;
                        }
                    }
                }
            }
            return ( bool ) pre [T] ;
        }
    public :
        MaxCostMaxFlow ( )  {  ecnt = 1 ; memset ( head, 0, sizeof head ) ;  }

        inline void clear ( )  {
            ecnt = 1 ; memset ( head, 0, sizeof head ) ;
        }

        inline void add_edge ( int u, int v, int w, int cost )  {
            g [++ ecnt] = ( edge )  {  v, head [u], w, cost } ; head [u] = ecnt ;
            g [++ ecnt] = ( edge )  {  u, head [v], 0, -cost } ; head [v] = ecnt ;
        }

        std :: pair < int, int > mcmf ( int S, int T )  {
            this -> S = S, this -> T = T ;
            int flow = 0, cost = 0, x ;
            while ( spfa ( S, T ) )  {
                x = oo ;
                for ( int i = pre [T] ; i ; i = pre [g [i ^ 1].to] )  chkmin ( x, g [i].w ) ;
                for ( int i = pre [T] ; i ; i = pre [g [i ^ 1].to] )  {
                    g [i].w -= x, g [i ^ 1].w += x ;
                    cost += x * g [i].cost ;
                }

                flow += x ;
            }
            return std :: make_pair ( flow, cost ) ;
        }
} Lazer2 ;

# undef N
# undef M

int main ( )  {
    int n, m ;
    scanf ( "%d%d", & n, & m ) ;
    const int S = n + m + 1, T = n + m + 2 ;
    for ( int i = 1 ; i <= n ; ++ i )  {
        static int x ;
        scanf ( "%d", & x ) ;
        Lazer1.add_edge ( S, i, x, 0 ) ;
        Lazer2.add_edge ( S, i, x, 0 ) ;
    }
    for ( int i = 1 ; i <= m ; ++ i )  {
        static int x ;
        scanf ( "%d", & x ) ;
        Lazer1.add_edge ( i + n, T, x, 0 ) ;
        Lazer2.add_edge ( i + n, T, x, 0 ) ;
    }

    for ( int i = 1 ; i <= n ; ++ i )
        for ( int j = 1 ; j <= m ; ++ j )  {
            static int c ;
            scanf ( "%d", & c ) ;
            Lazer1.add_edge ( i, j + n, oo, c ) ;
            Lazer2.add_edge ( i, j + n, oo, c ) ;
        }

    printf ( "%d\n%d\n", Lazer1.mcmf ( S, T ).second, Lazer2.mcmf ( S, T ).second ) ;

    return 0 ;
}
發佈了223 篇原創文章 · 獲贊 38 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章