[SP2063]MPIGS-Sell Pigs

题目

点这里看题目。

分析

蛮有意思的一道题目。

如果没有调整猪的操作,那么这就是一道简单的二分图问题。

考虑调整的操作。如果一次 (u_1,u_2,...,u_k) 的猪舍全部被打开了,那么就相当于在此之后,如果选到了 (u_1,u_2,u_3,...,u_k) 中的任意一个,这 (k) 个猪舍里的猪都是 " 共享 " 的。因此我们可以建立一个虚拟猪舍 (v) ,让 (k) 个猪舍里的猪全部流入 (v) ,并且直接用 (v) 替换这 (k) 个猪舍——从 (v) 连向顾客,并且在之后任何一次 (u_1,u_2,...,u_k) 中的猪舍被访问时,都从 (v) 开始连边。

有一点点类似于并查集的合并,只不过存在了时间的先后差异。

代码

#include <cstdio>
#include <algorithm>
using namespace std;

const int INF = 0x3f3f3f3f;
const int MAXN = 1e4 + 5, MAXM = 1e5 + 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 seq[MAXN], lst[MAXN];

int pig[MAXN], ned[MAXN];

int head[MAXN], dep[MAXN], cur[MAXN];
int N, M, 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( M ), read( N ); tot = N * 2 + M;
	const int PIG = 0, MAN = M, TRE = N + M;
	for( int i = 1 ; i <= M ; i ++ ) read( pig[i] ), lst[i] = i;
	for( int i = 1, A ; i <= N ; i ++ )
	{
		read( A );
		for( int j = 1 ; j <= A ; j ++ )
			read( seq[j] ), AddE( lst[seq[j]], i + TRE, INF );
		for( int j = 1 ; j <= A ; j ++ ) lst[seq[j]] = i + TRE;
		AddE( i + TRE, i + MAN, INF );
		read( ned[i] );
	}
	const int s = ++ tot, t = ++ tot;
	for( int i = 1 ; i <= M ; i ++ ) AddE( s, i + PIG, pig[i] );
	for( int i = 1 ; i <= N ; i ++ ) AddE( i + MAN, t, ned[i] );
	write( Dinic( s, t ) ), putchar( '
' );
	return 0;
}
原文地址:https://www.cnblogs.com/crashed/p/14193228.html