[BZOJ3996]-[TJOI2015]线性代数-最小割

版权声明:转载嘛....也不是不可以(故作沉思),记得带上me的ID啊qwq https://blog.csdn.net/Izumi_Hanako/article/details/80826930

说在前面

好久没写过了
可能已经傻了


题目

BZOJ3996传送门
看题可戳传送门


解法

把那个矩阵的贡献画出来
发现大概是这样的形式:选点 i 需要付出 c i 代价,如果同时选择 i , j ,获得 b i j 的收益
然后就最小割了

直接把贡献看成点,建成一个二分图一样的东西,跑的飞快不知道为啥
另外一种建图方法快一倍
这里写图片描述
感觉Doggu当初总结的东西很有道理啊


下面是代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;

int N , id[505][505] , ic[505] , S , T , id_c ;
int B[505][505] , C[505] , tp = 1 , head[300005] , All ;
struct Path{
    int pre , to , flow ;
} p[6000005] ;

void In( int t1 , int t2 , int t3 ){
    p[++tp] = ( Path ){ head[t1] , t2 , t3 } ; head[t1] = tp ;
    p[++tp] = ( Path ){ head[t2] , t1 , 0 } ; head[t2] = tp ;
}

void preWork(){
    for( int i = 1 ; i <= N ; i ++ )
        ic[i] = ++id_c ;
    S = ++id_c , T = ++id_c ;
    /*for( int i = 1 ; i <= N ; i ++ ){
        for( int j = 1 ; j <= N ; j ++ ){
            id[i][j] = ++id_c ;
            In( id[i][j] , T , B[i][j] ) , All += B[i][j] ;
            In( ic[i] , id[i][j] , 0x3f3f3f3f ) ;
            if( i != j ) In( ic[j] , id[i][j] , 0x3f3f3f3f ) ;
        } In( S , ic[i] , C[i] ) ;
    }*/
    for( int i = 1 ; i <= N ; i ++ ){
        int tmp = 0 ;
        for( int j = 1 ; j < i ; j ++ )
            In( j , i , B[i][j] + B[j][i] ) , tmp += B[i][j] + B[j][i] ;
        In( S , i , C[i] ) ;
        In( i , T , tmp + B[i][i] ) , All += tmp + B[i][i] ;
    }
}

int que[300005] , dis[300005] , fr , ba ;
bool Bfs(){
    memset( dis + 1 , -1 , sizeof( int ) * id_c ) ;
    fr = 1 , ba = 0 , que[++ba] = S , dis[S] = 0 ;
    while( ba >= fr ){
        int u = que[fr++] ;
        for( int i = head[u] ; i ; i = p[i].pre ){
            int v = p[i].to ;
            if( dis[v] != -1 || !p[i].flow ) continue ;
            dis[v] = dis[u] + 1 , que[++ba] = v ;
        }
    } return dis[T] != -1 ;
}

int dfs( int u , int flow ){
    if( u == T ) return flow ;
    int rt = 0 ;
    for( int i = head[u] ; i ; i = p[i].pre ){
        int v = p[i].to , nowf ;
        if( dis[v] != dis[u] + 1 || !p[i].flow ) continue ;
        if( ( nowf = dfs( v , min( p[i].flow , flow ) ) ) ){
            rt += nowf , flow -= nowf ;
            p[i].flow -= nowf , p[i^1].flow += nowf ;
            if( !flow ) break ;
        }
    } if( flow ) dis[u] = -1 ;
    return rt ;
}

void solve(){
    while( Bfs() )
        All -= dfs( S , 0x3f3f3f3f ) ;
    printf( "%d" , All ) ;
}

int main(){
    scanf( "%d" , &N ) ;
    for( int i = 1 ; i <= N ; i ++ )
        for( int j = 1 ; j <= N ; j ++ )
            scanf( "%d" , &B[i][j] ) ;
    for( int i = 1 ; i <= N ; i ++ )
        scanf( "%d" , &C[i] ) ;
    preWork() ; solve() ;
}

猜你喜欢

转载自blog.csdn.net/Izumi_Hanako/article/details/80826930