ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[NOI2012] 美食节

2021-01-08 21:34:42  阅读:222  来源: 互联网

标签:int Graph 厨师 delt NOI2012 prev 美食节 sink


题目

点这里看题目。

分析

本题的弱化版便是[SCOI2007]修车

考虑现在有 \(n\) 份菜给一位厨师做,时间分别为 \(t_1,t_2,\dots,t_n\) ,总等待时间为:

\[\sum_{i=1}^n\sum_{j=1}^it_{j}=\sum_{j=1}^nt_j(n-j+1)=\sum_{j=1}^nj\times t_{n-j+1} \]

由于 \(t\) 的顺序任意,所以我们可以将时间分摊到每份菜上面,即可以直接认为第 \(i\) 份菜的花费为 \(i\times t_i\) 。

注意到费用同时收菜的种类,厨师身份和做菜顺序三个影响,于是可以想到如下建图方式:

  • 对于 \(m\) 位厨师,每位厨师拆成 \(p\) 个点,点 \((i,j)\) 表示厨师 \(i\) 正在做第 \(j\) 道菜;对于每个点 \((i,j)\) 连向汇点,容量为 1 ,费用为 0 。
  • 对于 \(n\) 道菜,建立 \(n\) 个点,源点向第 \(i\) 道菜连接边,容量为 \(p\) ,费用为 0 。
  • 对于第 \(i\) 道菜和任意个厨师点 \((x,y)\) ,连接 \(i\rightarrow (x,y)\) ,容量为 1 ,费用为 \(y\times t_{i,x}\) 。

注意到一个重要的性质:在费用最小的情况下,每道菜的制作时间必然会尽量地靠前,因此不会出现做菜中断的情况。


但是这里,这种暴力建图方法会......直接 T 飞。

问题很明显,点太多,导致边也太多。我们需要减少点数。

回到性质,可以得出:如果第 \(i\) 个厨师都还没有做第 \(j\) 道菜,那么他也不可能做 \(j+1\) 道, \(j+2\) 道以及更多的菜。也即,我们只需要在图上加入第 \(i\) 个厨师的第一道未做的菜,而剩余的点,则完全可以在做完一道菜之后再加入到图中。

注意本题的 " 做菜 " 实际上就是在图上推流量为 1 的流,所以我们每次推流之后都需要加点。可以发现这样的点数就是 \(O(m+p)\) ,边数就是 \(O(n(m+p))\) ,再加上玄学的网络流复杂度就可以通过了。

小结:

  1. 拆分代价的思想,使得代价最终与顺序无关
  2. 对于单调性质的利用,从而删除多余点,优化的点、边数量。

代码

#include <cstdio>

#define rep( i, a, b ) for( int (i) = (a) ; (i) <= (b) ; ++ (i) )
#define per( i, a, b ) for( int (i) = (a) ; (i) >= (b) ; -- (i) )

typedef long long LL;

const int INF = 0x3f3f3f3f;
const int MAXN = 1e6 + 5, MAXM = 1e6 + 5;
const int MAXS = 1e3 + 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, w, c;
}Graph[MAXM << 1];

int q[MAXN], fro, rea;

int tim[MAXS][MAXS];
int id[MAXS][MAXS], len[MAXS];

int head[MAXN], dist[MAXN], cur[MAXN], bel[MAXN], prev[MAXN];
int N, M, cnt = 1, tot, source, sink;
bool vis[MAXN];

void AddEdge( const int from, const int to, const int C, const int W )
{
	Graph[++ cnt].to = to, Graph[cnt].nxt = head[from];
	Graph[cnt].c = C, Graph[cnt].w = W, head[from] = cnt;
}

void AddE( const int from, const int to, const int C, const int W ) { AddEdge( from, to, C, W ), AddEdge( to, from, 0, -W ); }

#define Nxt( x ) ( x = ( x + 1 ) % MAXN )

bool SPFA( const int S, const int T )
{
	int u, v; fro = rea = 0;
	rep( i, 1, tot ) dist[i] = INF, prev[i] = 0;
	dist[q[rea] = S] = 0, vis[S] = true, Nxt( rea );
	while( fro ^ rea )
	{
		vis[u = q[fro]] = false, Nxt( fro );
		for( int i = head[u] ; i ; i = Graph[i].nxt )
			if( Graph[i].c && dist[v = Graph[i].to] > dist[u] + Graph[i].w )
			{
				dist[v] = dist[u] + Graph[i].w, prev[v] = i;
				if( ! vis[v] ) vis[q[rea] = v] = true, Nxt( rea );
			}
	}
	return dist[T] < INF;
}

void Add( const int j )
{
	bel[id[j][++ len[j]] = ++ tot] = j;
	rep( i, 1, N ) AddE( i, id[j][len[j]], 1, tim[i][j] * len[j] );
	AddE( id[j][len[j]], sink, 1, 0 );
}

int main()
{
	read( N ), read( M ), tot = N, source = ++ tot, sink = ++ tot;
	rep( i, 1, N ) { int p; read( p ), AddE( source, i, p, 0 ); }
	rep( i, 1, N ) rep( j, 1, M ) read( tim[i][j] );
	rep( j, 1, M ) Add( j );
	
	LL cost = 0; int delt;
	while( SPFA( source, sink ) )
	{
		delt = INF;
		for( int u = sink ; u ^ source ; u = Graph[prev[u] ^ 1].to ) delt = MIN( delt, Graph[prev[u]].c );
		for( int u = sink ; u ^ source ; u = Graph[prev[u] ^ 1].to ) Graph[prev[u]].c -= delt, Graph[prev[u] ^ 1].c += delt;
		cost += delt * dist[sink], Add( bel[Graph[prev[sink] ^ 1].to] );
	}
	write( cost ), putchar( '\n' );
	return 0;
}

标签:int,Graph,厨师,delt,NOI2012,prev,美食节,sink
来源: https://www.cnblogs.com/crashed/p/14253437.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有