zoukankan      html  css  js  c++  java
  • G_M_C_美食节

    美食节

    题解:学习了动态加边,可以说是进一步理解了网络流。具体思路就是考虑每一道菜,如果这是该位厨师最后一次做,那么等待时间就是做这道菜的时间,如果是倒数第二次做,就要两倍时间(目前做了一次,后面还有等待的一次时间)……,对于其他菜以此类推。那么可以这样考虑,当这位厨师倒一次做的边没有流量的时候,是不可能用到倒二次做的边(因为费用流会优先选择费用小的边,而我们的时间花费即为费用,故倒一次没用不可能使用倒二次),于是乎可以在跑完每次最短路的时候,判断这次是从哪个厨师的哪个点转移来的,紧接着连上接下来的一个点(倒一就连倒二,倒二就倒三……)。

    #pragma comment(linker, "/STACK: 1024000000,1024000000")
    #include <bits/stdc++.h>
    #define pb push_back
    #define mp make_pair
    #define eb emplace_back
    #define em emplace
    #define pii pair<int,int>
    #define de(x) cout << #x << " = " << x << endl
    #define clr(a,b) memset(a,b,sizeof(a))
    #define INF (0x3f3f3f3f)
    #define LINF ((long long)(0x3f3f3f3f3f3f3f3f))
    #define F first
    #define S second
    using namespace std;
    inline int getint()
    {
      int _x=0; char _tc=getchar();
      while(_tc<'0'||_tc>'9') _tc=getchar();
      while(_tc>='0'&&_tc<='9') _x*=10,_x+=(_tc-'0'),_tc=getchar();
      return _x;
    }
    
    const int M = 1e5 + 15;
    const int N = 110;
    int T[N][N];
    int p[N], P;
    int n, m, st, ed;
    struct Edge
    {
    	int u, v, c, w, nxt;
    	Edge(){}
    	Edge( int t2, int t3, int t4, int t5, int t6 ) :
    		u(t2), v(t3), c(t4), w(t5), nxt(t6) {}
    };
    Edge e[M<<4];
    int ect;
    int pr[M], h[M], d[M];
    bool vis[M];
    int ans = 0;
    
    void _add( int u, int v, int c, int w )
    {
    	e[ect].u = u; e[ect].v = v; e[ect].c = c; e[ect].w = w; e[ect].nxt = h[u]; h[u] = ect ++;
    	e[ect].u = v; e[ect].v = u; e[ect].c = 0; e[ect].w = -w; e[ect].nxt = h[v]; h[v] = ect ++;
    }
    
    void init()
    {
    	clr(h,-1);
    	P = ect = 0;
    }
    bool spfa()
    {
    	clr(d,INF);
    	clr(vis,false);
    	clr(pr,-1);
    	queue<int> Q;
    	Q.push( st );
    	d[st] = 0;
    	vis[st] = true;
    	while ( !Q.empty() )
    	{
    		int u = Q.front(); Q.pop();
    		vis[u] = false;
    		for ( int i = h[u]; i + 1; i = e[i].nxt )
    		{
    			int v = e[i].v;
    			if ( e[i].c > 0 && d[v] > d[u] + e[i].w )
    			{
    				d[v] = d[u] + e[i].w;
    				pr[v] = i;
    				if ( !vis[v] )
    				{
    					vis[v] = true;
    					Q.push(v);
    				}
    			}
    		}
    	}
    	return d[ed] != INF;
    }
    
    void mcf()
    {
    	int f = INF;
    	for ( int i = ed; i != st; i = e[pr[i]].u )
    		f = min( f, e[pr[i]].c );
    	for ( int i = ed; i != st; i = e[pr[i]].u )
    	{
    		e[pr[i]].c -= f, e[pr[i]^1].c += f;
    		ans += f*e[pr[i]].w;
    	}
    	int x = e[pr[ed]].u;
    	int nw = (x-n-1)/P + 1, th = (x-n)%P + 1;
    	if ( th <= P )
    	{
    		for ( int i = 1; i <= n; i ++ )
    			_add( i, n+(nw-1)*P+th, 1, th*T[i][nw] );
    	}
    	_add( n+(nw-1)*P+th, ed, 1, 0 );
    }
    
    int main()
    {
    	init();
    	scanf("%d%d", &n, &m);
    	for ( int i = 1; i <= n; i ++ )
    		scanf("%d", &p[i]), P += p[i];
    	for ( int i = 1; i <= n; i ++ )
    		for ( int j = 1; j <= m; j ++ )
    			scanf("%d", &T[i][j]);
    	st = 0, ed = n + 1 + P*m;
    	for ( int i = 1; i <= n; i ++ )
    	{
    		_add( st, i, p[i], 0 );
    		for ( int j = 1; j <= m; j ++ )
    			_add( i, n+(j-1)*P+1, 1, T[i][j] );
    	}
    	for ( int i = 1; i <= m; i ++ )
    		_add( n+(i-1)*P+1, ed, 1, 0 );
    	while ( spfa() ) mcf();
    	printf("%d
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    php判断是不是https的方法
    [Redis] Redis哨兵模式部署
    Transformer详解:各个特征维度分析推导
    Hell World:)
    cesiumjs
    UVA-11090 Going in Cycle!!
    判断两个数组是否相似 (arraysSimilar)
    Markdown 语法说明 (简体中文版)
    DjangoModels
    Lua 学习 chapter30 编写c函数的技巧
  • 原文地址:https://www.cnblogs.com/FormerAutumn/p/10527047.html
Copyright © 2011-2022 走看看