• [LG P1361]小M的作物


    题目

    点这里看题目。

    分析

    经典的一类最小割问题。

    首先不难确定问题的方向是最小割,以下我们认为 (uin S) 表示种在 (A) 田, (uin T) 表示种在 (B) 田。

    考虑如果没有合种的额外贡献,我们可以对于每个点,连接 (Soverset{a_u}{ ightarrow } u)(uoverset{b_u}{ ightarrow } T)

    那么此时有合种的贡献,我们不妨先加到初始值,再考虑什么时候会删除。

    由于在两田的合种本质相似,所以我们只考虑在 (A) 田合种的贡献。考虑给方案建立一个节点 (p) ,那么 (pin S) 此时就可以看作是作物全部要种在 (A) 田;这就意味着如果 (S) 可以通过 (p) 和作物 (u) 到达 (T) 则不合法,因此需要保证此时只能割掉 (u ightarrow T) 的边,因此连接 (poverset{+infty}{ ightarrow } u)

    (B) 田合种的情况相似操作即可。

    小结:

    1. 最小割的思考方式都很类似,都是构造边使得不合法情况下边会被割掉
    2. 这种建图方式可以解决很多某些点需要属于同一集合的要求。

    代码

    #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( '
    ' );
    	return 0;
    }
    
  • 相关阅读:
    Codeforces训练记录
    2017中国大学生程序设计竞赛-杭州站
    Codeforces Round #636 (Div. 3)
    自适应Simpson积分
    2020牛客暑期多校训练营(第九场)- E. Groundhog Chasing Death
    2020 Multi-University Training Contest 6
    拉格朗日插值法学习笔记
    二次剩余学习笔记
    2020 Multi-University Training Contest 3
    2020 Multi-University Training Contest 2
  • 原文地址:https://www.cnblogs.com/crashed/p/14203567.html
Copyright © 2020-2023  润新知