zoukankan      html  css  js  c++  java
  • bzoj1391 最大权闭合子图(also最小割、网络流)

    一道裸的最小割的题,写一下只是练练手。

    表示被卡M,RE不开心。一道裸题至于吗?

    再次复习一下最大权闭合子图:

    1.每一个点若为正权,与源点连一条容量为绝对值权值的边。否则连向汇点一条容量为绝对值权值的边

    2.如果有选了A点才能选B点的约束条件,且违背这个约束条件有C的代价,则从A点向B点连一条容量为C的边(如果不能违背,则连一条容量为INF的边)

    3.设源点出度为C,最大流的值为D。答案为C-D。

    #include<cstdio>
    #include<queue>
    #include<algorithm>
    using namespace std ; 
    
    
    namespace DINIC {
    
        const int MAXVn = 1200 * 2 + 20 ; 
        const int MAXEn = 1200 * 2 + 20 ;
        int Vn ; 
    
        struct edge {
            int p ; 
            int c ; 
            edge * nxt ; 
            edge * brother ; 
        } ;
    
        edge E [ MAXEn * 2 ] ; 
        namespace E_SET { edge * T = E ; } ;  
        edge * V [ MAXVn ] ; 
    
        int S , T ;
    
        void add_edge ( const int a , const int b , const int f ) {
            using E_SET :: T ; 
            T -> p = b ; T -> c = f ; T -> nxt = V [ a ] ; V [ a ] = T ++ ;
            T -> p = a ; T -> c = 0 ; T -> nxt = V [ b ] ; V [ b ] = T ++ ; 
            V [ a ] -> brother = V [ b ] ; V [ b ] -> brother = V [ a ] ; 
        }
    
        edge * cur [ MAXVn ] ;
        int dis [ MAXVn ] ; 
    
        bool bfs ( ) {
            queue < int > q ; 
            fill ( dis , dis + Vn , - 1 ) ;    
            copy ( V , V + Vn , cur ) ; 
            q . push ( S ) ; dis [ S ] = 0 ; 
            while ( ! q . empty () ) {
                const int o = q . front () ; q . pop () ; 
                for ( edge * v = V [ o ] ; v != 0 ; v = v -> nxt ) 
                    if ( v -> c != 0 && dis [ v -> p ] == - 1 ) {
                        dis [ v -> p ] = dis [ o ] + 1 ; 
                        q . push ( v -> p ) ;
                    }
            }
            return dis [ T ] != -1 ; 
        }
    
        int dfs ( const int o , int flow ) {
            if ( o == T || flow == 0 ) return flow ; 
            int f , ans = 0 ; 
            for ( edge * & v = cur [ o ] ; v != 0 ; v = v -> nxt ) 
            if ( dis [ o ] + 1 == dis [ v -> p ] && 
                ( f = dfs ( v -> p , min ( flow , v -> c ) ) ) != 0 ) {
                v -> c -= f ; v -> brother -> c += f ; 
                ans += f ; flow -= f ;
                if ( flow == 0 ) break ;
            }
            return ans ; 
        }
    
        int dinic ( ) {
            int ans = 0 ; 
            while ( bfs ( ) ) ans += dfs ( S , 1 << 30 ) ;
            return ans ; 
        }
    
    }
    
    int M , N ;
    int sum ; 
    
    int main () {
    
        using namespace DINIC ;  
        scanf ( "%d%d" , & N , & M ) ;
        Vn = M + N + 2 ; //in && out && S && T 
        S = 0 ; 
        T = 1 ; 
    
    #define WORK(a) ((a)+2)
    #define MACHINE(a) ((a)+N+2)
    
         for ( int i = 0 ; i < N ; ++ i ) {
            int value_of_w , num_of_w ; scanf ( "%d%d" , & value_of_w , & num_of_w ) ;
            sum += value_of_w ; 
            add_edge ( S , WORK(i) , value_of_w ) ;     
            while ( num_of_w -- ) {
                int n , pay ; 
                scanf ( "%d%d" , & n , & pay ) ;
                n -= 1 ; 
                add_edge ( WORK(i) , MACHINE(n) , pay ) ;
            }
        }
        for ( int i = 0 ; i < M ; ++ i ) {
            int pay ; scanf ( "%d" , & pay ) ;
            add_edge ( MACHINE(i) , T , pay ) ;
        }
    
    #undef WORK 
    #undef MACHINE
    
        printf ( "%d
    " , sum - dinic () ) ; 
    
        return 0 ; 
    
    }
  • 相关阅读:
    Hanlp(汉语言处理包)配置、使用、官方文档
    Mysql 在DOS窗口下的操作
    漂亮的省级下拉选择
    数组的应用排序
    设置外部样式坐标的位置
    动态设置Div坐标
    对联广告
    树形菜单
    隐藏图和图框架
    使用clssneme改变图片或样式
  • 原文地址:https://www.cnblogs.com/Christopher-Cao/p/5185634.html
Copyright © 2011-2022 走看看