zoukankan      html  css  js  c++  java
  • [CF103E]Buying Sets

    题目

    点这里看题目。

    分析

    首先,对所有子集的权值取反,问题变成了求最大的权值和,可以尝试最小割。

    这里的最小割就类似最大闭合权子图。将子集和元素都抽象成一个点,对于集合 (U)(uin U) ,连接 (Uoverset{+infty}{ ightarrow} u) ;对于子集,连接 (soverset{w_U}{ ightarrow} U)

    现在还不能保证子集的并的大小恰好为自己个数。不过根据题目条件,元素个数必然不少于子集个数

    如果元素本身选择时存在一个很大的代价 (C),那么最小割必然会少选元素;相应地,我们给每个 (U)(w_U) 也加上 (C) ,那么最后必然会少选元素多选集合,并且由于 (C) 真的很大,只要多选一个元素,代价就差了十万八千里。因此如果存在符合条件的集族,我们一定会选择这样的集族让 (C) 抵消

    给每个元素增加 (C) 的代价,给每个子集增加 (C) 的贡献,建图跑最大权闭合子图即可。

    小结:

    使用(极大、极小)参数调整割的方案是一个很巧妙也很有借鉴意义的方法。事实上 wqs 二分中也有类似的思想。

    代码

    #include <cstdio>
    
    typedef long long LL;
    
    const int INF = 0x3f3f3f3f, SMA = 5e7;
    const int MAXN = 2e5 + 5, MAXM = 2e5 + 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 head[MAXN], dep[MAXN], cur[MAXN];
    int N, 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;
    }
    
    int main()
    {
    	read( N ), tot = N << 1;
    	const int s = ++ tot, t = ++ tot;
    	for( int i = 1, m ; i <= N ; i ++ )
    	{
    		read( m );
    		for( int to ; m -- ; )
    			read( to ), AddE( i, to + N, INF );
    	}
    	int ans = 0;
    	for( int i = 1, v ; i <= N ; i ++ )
    	{
    		read( v ), ans += ( v = SMA - v );
    		AddE( s, i, v ), AddE( i + N, t, SMA );
    	}
    	write( MIN( 0, Dinic( s, t ) - ans ) ), putchar( '
    ' );
    	return 0;
    }
    
  • 相关阅读:
    SqlServer事务日志满的解决方案
    关于.net反射和metadata加载致Jeffray Zhao等几位和firelong
    Context Root选/的原则
    [继续讨论]关于Windows PE和.net assembly的加载
    有趣的重写GetType()方法
    对Wintercn关于函数式编程的文章评论
    The experience to config Cisco 2811 for VOIP
    关于c#静态方法和实例方法的辨析和应用
    防止刷新时,密码输入框中的信息丢失
    计算百分比 JS
  • 原文地址:https://www.cnblogs.com/crashed/p/14193122.html
Copyright © 2011-2022 走看看