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\n" , sum - dinic () ) ; return 0 ; }