zoukankan      html  css  js  c++  java
  • P2050 [NOI2012]美食节

    首先所有菜要被做完,那对于每种菜分配它个数个流量

    发现一个同学需要等待的时间仅和他选择的厨师第几个做他的菜有关,考虑将厨师第几次做菜拆成点

    如果厨师是倒数第 (k) 个做,则有 (k a[i][j]) 个代价被等待后 (k) 个菜的同学贡献

    本身费用流这种算法就有浓重的贪心(最短路)气息,我们可以根据它贪心(最短路)的特性,进行一些边数上的优化

    考虑一个厨师,如果倒数第一道菜没被做的话,一定不会做倒数第二道

    因为第一道菜的边权最小,从最短路的角度考虑一定会选它

    每次都在最后一道菜被选后再连其他的边,就可以优化了

    //#include <bits/stdc++.h>
    #include <queue>
    #include <iostream>
    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #pragma GCC optimize(2)
    using namespace std;
    #define rg register
    //#ifdef ONLINE_JUDGE
    //char ss[1 << 17], *A = ss, *B = ss;
    //inline char getchar(){ if(A == B){ B = (A = ss) + fread(ss, 1, 1 << 17, stdin); if(A == B) return EOF; } return *A++; }
    //#endif
    inline int read(){
        rg char ch = getchar();
        rg int x = 0, f = 0;
        while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
        while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
        return f ? -x : x;
    }
    #define rep(i, a, b) for(int i = a; i <= b; ++i)
    #define req(i, a ,b) for(int i = a; i >= b; --i)
    const int N = 100 * 800 + 45, M = N * 20; 
    int head[N], ver[M], nxt[M], flow[M], edge[M], tot = 1;
    inline void add(int x, int y, int f, int z){
        ver[++tot] = y;
        nxt[tot] = head[x];
        head[x] = tot;
        edge[tot] = z;
        flow[tot] = f;
    }
    inline void adds(int x, int y, int f, int z){
        add(x, y, f, z);
        add(y, x, 0, -z);
    }
    int maxpoint;
    int n, m, S, T;
    int suma[55], p[105][105];
    #define inf 0x3f3f3f3f
    int v[N], dis[N], pre[N];
    template <typename T> inline void ckmax(T &a, const T &b){ if(a < b) a = b; }
    inline int spfa(){
    	queue<int> q;
    	q.push(S);
        rep(i, 1, maxpoint) dis[i] = inf;
        dis[T] = inf;
        dis[S] = 0;
        while(!q.empty()){
            int x = q.front(); q.pop();
            v[x] = false;
            for(int i = head[x]; i; i = nxt[i]){
                int y = ver[i];
                if(dis[y] > dis[x] + edge[i] && flow[i]){
                    dis[y] = dis[x] + edge[i];
                    pre[y] = i;
                    if(!v[y]){
                        q.push(y);
    					v[y] = true;
    //                    if(!q.empty() && dis[y] < dis[q.front()]) q.push_front(y);
    //                    else q.push_back(y);
                    }
                }
            }
        }
        return dis[T] != inf;
    }
    template <typename T> inline void ckmin(T &a, const T &b){ if(a > b) a = b; }
    int cnt[N];
    inline int MCMF(){
        int ans = 0;
        rep(i, 1, m) cnt[i] = 1;
        rep(i, 1, n) rep(j, 1, m) adds(i, n + j, 1, p[i][j]);
        while(spfa()){
            for(int i = pre[T]; i; i = pre[ver[i ^ 1]]) flow[i] -= 1, flow[i ^ 1] += 1;
            ans += dis[T];
    		int to = (ver[pre[T] ^ 1] - n - 1) % m + 1;
            ++cnt[to];
            ckmax(maxpoint, n + (cnt[to] - 1) * m + to);
    		rep(i, 1, n) adds(i, n + (cnt[to] - 1) * m + to, 1, cnt[to] * p[i][to]); 
    		adds(n + (cnt[to] - 1) * m + to, T, 1, 0);
        }
        return ans;
    }
    signed main(){
        n = read(), m = read();
        int sum = 0;
        rep(i, 1, n) sum += (suma[i] = read());
        S = 0; T = n + sum * m + 1;
        rep(i, 1, n) rep(j, 1, m) p[i][j] = read();
        rep(i, 1, n) adds(S, i, suma[i], 0);
        rep(i, 1, m) adds(n + i, T, 1, 0);
        maxpoint = n + m;
        cout<<MCMF()<<endl;
        getchar(); getchar();
        return 0;
    }
  • 相关阅读:
    hadoop2.2编程:MRUnit测试
    TestLinkConverter编程纪要
    Redisson的分布式锁的简单实现
    Jmeter工具使用
    JVM的学习(三)
    Mybatis需要注意的地方及知识点
    JVM学习二(JAVA的四种引用)
    mysql的引擎
    JVM学习一(JVM的内存结构和垃圾回收)
    JDk1.8HashMap的源码分析
  • 原文地址:https://www.cnblogs.com/XiaoVsun/p/13100063.html
Copyright © 2011-2022 走看看