1. 程式人生 > >[BZOJ3996]-[TJOI2015]線性代數-最小割

[BZOJ3996]-[TJOI2015]線性代數-最小割

說在前面

好久沒寫過了
可能已經傻了


題目

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() ; }