BZOJ-2668: [cqoi2012]交换棋子(费用流)

作者: AmadeusChan | 来源:发表于2018-11-19 18:22 被阅读0次

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

    建模有点神奇,然后就直接费用流了。

    代码:

    #include <cstdio>
    
    #include <algorithm>
    
    #include <cstring>
    
     
    
    using namespace std ;
    
     
    
    #define maxv maxn * maxn *3
    
    #define maxn 25
    
    #define inf 0x7fffffff
    
    #define check( x , y ) ( x >0&& y >0&& x <= n && y <= m )
    
     
    
    char s[2][ maxn ][ maxn ], w[ maxn ][ maxn ];
    
    int n , m , node[ maxn ][ maxn ][3], V =0;
    
     
    
    struct network{
    
        
    
        struct edge{
    
            edge *next ,*pair ;
    
            int t , f , c ;
    
        }*head[ maxv ];
    
        
    
        int S , T ;
    
        
    
        network(  ){
    
            memset( head ,0,sizeof( head ));
    
        }
    
        
    
        void Add(int s ,int t ,int f ,int c ){
    
            edge *p =new( edge );
    
            p -> t = t , p -> f = f , p -> c = c , p -> next = head[ s ];
    
            head[ s ]= p ;
    
        }
    
        
    
        void AddEdge(int s ,int t ,int f ,int c ){
    
            Add( s , t , f , c ),Add( t , s ,0,- c );
    
            head[ s ]-> pair = head[ t ], head[ t ]-> pair = head[ s ];
    
        }
    
        
    
        int dist[ maxv ], slack[ maxv ], Maxflow , Mincost ;
    
        bool f[ maxv ];
    
        
    
        int aug(int v ,int flow ){
    
            if( v == T ){
    
                Maxflow += flow , Mincost += flow * dist[ S ];
    
                return flow ;
    
            }
    
            int rec =0; f[ v ]=false;
    
            for( edge *p = head[ v ]; p ; p = p -> next )if( f[ p -> t ]&& p -> f ){
    
                if( dist[ v ]== dist[ p -> t ]+ p -> c ){
    
                    int ret =aug( p -> t ,min( flow - rec , p -> f ));
    
                    p -> f -= ret , p -> pair -> f += ret ;
    
                    if(( rec += ret )== flow )return flow ;
    
                }else slack[ p -> t ]=min( slack[ p -> t ], dist[ p -> t ]+ p -> c - dist[ v ]);
    
            }
    
            return rec ;
    
        }
    
        
    
        bool relabel(  ){
    
            int delta = inf ;
    
            for(int i =0; i ++< T ;)if( f[ i ]) delta =min( delta , slack[ i ]);
    
            if( delta == inf )return false;
    
            for(int i =0; i ++< T ;)if(! f[ i ]) dist[ i ]+= delta ;
    
            return true;
    
        }
    
        
    
        void costflow(  ){
    
            Maxflow = Mincost =0;
    
            memset( dist ,0,sizeof( dist ));
    
            do{
    
                for(int i =0; i ++< T ;) slack[ i ]= inf ;
    
                do{
    
                    memset( f ,true,sizeof( f ));
    
                }while(aug( S , inf ));
    
            }while(relabel(  ));
    
        }
    
        
    
    } net ;
    
     
    
    int cnt[2], counter =0;
    
     
    
    const int dir[8][2]={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
    
     
    
    int main(  ){
    
        scanf("%d%d",&n ,&m );
    
        cnt[0]= cnt[1]=0;
    
        for(int i =0; i ++< n ;){
    
            scanf("%s", s[0][ i ]+1);
    
            for(int j =0; j ++< m ;)if( s[0][ i ][ j ]=='1'){
    
                ++ cnt[0];
    
            }
    
        }
    
        for(int i =0; i ++< n ;){
    
            scanf("%s", s[1][ i ]+1);
    
            for(int j =0; j ++< m ;)if( s[1][ i ][ j ]=='1'){
    
                ++ cnt[1];
    
            }
    
        }
    
        if( cnt[0]!= cnt[1]){
    
            printf("-1\n");return 0;
    
        }
    
        for(int i =0; i ++< n ;)scanf("%s", w[ i ]+1);
    
        for(int i =0; i ++< n ;)for(int j =0; j ++< m ;){
    
            for(int k =0; k <3;++ k ) node[ i ][ j ][ k ]=++ V ;
    
        }
    
        net.S =++ V ; net.T =++ V ;
    
        for(int i =0; i ++< n ;)for(int j =0; j ++< m ;){
    
            if( s[0][ i ][ j ]!= s[1][ i ][ j ]){
    
                if( s[0][ i ][ j ]=='1'){
    
                    ++ counter ;
    
                    net.AddEdge( net.S , node[ i ][ j ][0],1,0);
    
                    net.AddEdge( node[ i ][ j ][0], node[ i ][ j ][2],( w[ i ][ j ]-'0'+1)/2,0);
    
                    net.AddEdge( node[ i ][ j ][1], node[ i ][ j ][0],( w[ i ][ j ]-'0')/2,0);
    
                }else{
    
                    net.AddEdge( node[ i ][ j ][0], net.T ,1,0);
    
                    net.AddEdge( node[ i ][ j ][0], node[ i ][ j ][2],( w[ i ][ j ]-'0')/2,0);
    
                    net.AddEdge( node[ i ][ j ][1], node[ i ][ j ][0],( w[ i ][ j ]-'0'+1)/2,0);
    
                }
    
            }else{
    
                net.AddEdge( node[ i ][ j ][1], node[ i ][ j ][0],( w[ i ][ j ]-'0')/2,0);
    
                net.AddEdge( node[ i ][ j ][0], node[ i ][ j ][2],( w[ i ][ j ]-'0')/2,0);
    
            }
    
            for(int k =0; k <8;++ k ){
    
                int x = i + dir[ k ][0], y = j + dir[ k ][1];
    
                if(check( x , y )){
    
                    net.AddEdge( node[ i ][ j ][2], node[ x ][ y ][1], inf ,1);
    
                }
    
            }
    
        }
    
        net.costflow(  );
    
        if( net.Maxflow < counter )printf("-1\n");else printf("%d\n", net.Mincost );
    
        return 0;
    
    }
    

    相关文章

      网友评论

        本文标题:BZOJ-2668: [cqoi2012]交换棋子(费用流)

        本文链接:https://www.haomeiwen.com/subject/kzbafqtx.html