[BZOJ3996]-[TJOI2015]線性代數-最小割
阿新 • • 發佈:2018-11-11
說在前面
好久沒寫過了
可能已經傻了
題目
BZOJ3996傳送門
看題可戳傳送門
解法
把那個矩陣的貢獻畫出來
發現大概是這樣的形式:選點
需要付出
代價,如果同時選擇
,獲得
的收益
然後就最小割了
直接把貢獻看成點,建成一個二分圖一樣的東西,跑的飛快不知道為啥
另外一種建圖方法快一倍
感覺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() ;
}