[LG P1361]小M的作物
阿新 • • 發佈:2020-12-28
題目
點這裡看題目。
分析
經典的一類最小割問題。
首先不難確定問題的方向是最小割,以下我們認為 \(u\in S\) 表示種在 \(A\) 田, \(u\in T\) 表示種在 \(B\) 田。
考慮如果沒有合種的額外貢獻,我們可以對於每個點,連線 \(S\overset{a_u}{\rightarrow } u\) 和 \(u\overset{b_u}{\rightarrow } T\) 。
那麼此時有合種的貢獻,我們不妨先加到初始值,再考慮什麼時候會刪除。
由於在兩田的合種本質相似,所以我們只考慮在 \(A\) 田合種的貢獻。考慮給方案建立一個節點 \(p\) ,那麼 \(p\in S\)
\(B\) 田合種的情況相似操作即可。
小結:
- 最小割的思考方式都很類似,都是構造邊使得不合法情況下邊會被割掉。
- 這種建圖方式可以解決很多某些點需要屬於同一集合的要求。
程式碼
#include <cstdio> typedef long long LL; #define int LL const int INF = 0x3f3f3f3f; const int MAXN = 2e5 + 5, MAXM = 2e6 + 5; template<typename _T> void read( _T &x ) { x = 0; char s = getchar(); int f = 1; while( s < '0' || '9' < s ) { f = 1; if( s == '-' ) f = -1; s = getchar(); } while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ); s = getchar(); } x *= f; } template<typename _T> void write( _T x ) { if( x < 0 ) putchar( '-' ), x = -x; if( 9 < x ) write( x / 10 ); putchar( x % 10 + '0' ); } template<typename _T> _T MIN( const _T a, const _T b ) { return a < b ? a : b; } struct Edge { int to, nxt, c; }Graph[MAXM << 1]; int q[MAXN]; int A[MAXN], B[MAXN]; int head[MAXN], dep[MAXN], cur[MAXN]; int N, K, cnt = 1, tot; void AddEdge( const int from, const int to, const int C ) { Graph[++ cnt].to = to, Graph[cnt].nxt = head[from]; Graph[cnt].c = C, head[from] = cnt; } void AddE( const int from, const int to, const int C ) { AddEdge( from, to, C ), AddEdge( to, from, 0 ); } bool BFS( const int S, const int T ) { int h = 1, t = 0, u, v; for( int i = 1 ; i <= tot ; i ++ ) dep[i] = INF; dep[q[++ t] = S] = 0; while( h <= t ) { u = q[h ++]; for( int i = head[u] ; i ; i = Graph[i].nxt ) if( Graph[i].c && dep[v = Graph[i].to] > dep[u] + 1 ) dep[q[++ t] = v] = dep[u] + 1; } return dep[T] < INF; } int DFS( const int u, const int lin, const int T ) { if( u == T ) return lin; int used = 0, ret, v, c; for( int &i = cur[u] ; i ; i = Graph[i].nxt ) { v = Graph[i].to, c = Graph[i].c; if( dep[v] == dep[u] + 1 && c && ( ret = DFS( v, MIN( lin - used, c ), T ) ) ) { used += ret, Graph[i].c -= ret, Graph[i ^ 1].c += ret; if( used == lin ) break; } } if( used < lin ) dep[u] = INF; return used; } int Dinic( const int S, const int T ) { int f = 0; while( BFS( S, T ) ) { for( int i = 1 ; i <= tot ; i ++ ) cur[i] = head[i]; f += DFS( S, INF, T ); } return f; } signed main() { read( N ); int ans = 0; for( int i = 1 ; i <= N ; i ++ ) read( A[i] ); for( int i = 1 ; i <= N ; i ++ ) read( B[i] ); read( K ), tot = N + 2 * K; const int s = ++ tot, t = ++ tot; for( int i = 1 ; i <= K ; i ++ ) { int k, c1, c2; read( k ); read( c1 ), read( c2 ), ans += c1 + c2; AddE( s, i + N, c1 ), AddE( i + N + K, t, c2 ); for( int to ; k -- ; ) read( to ), AddE( i + N, to, INF ), AddE( to, i + N + K, INF ); } for( int i = 1 ; i <= N ; i ++ ) if( A[i] > B[i] ) AddE( s, i, A[i] - B[i] ), ans += A[i]; else AddE( i, t, B[i] - A[i] ), ans += B[i]; write( ans - Dinic( s, t ) ), putchar( '\n' ); return 0; }