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;
    }
  • 相关阅读:
    现代软件工程 第一章 概论 第3题——韩婧
    现代软件工程 第一章 概论 第2题——韩婧
    小组成员邓琨、白文俊、张星星、韩婧
    UVa 10892 LCM的个数 (GCD和LCM 质因数分解)
    UVa 10780 幂和阶乘 求n!中某个因子的个数
    UVa 11859 除法游戏(Nim游戏,质因子)
    Codeforces 703C Chris and Road 二分、思考
    Codeforces 703D Mishka and Interesting sum 树状数组
    hdu 5795 A Simple Nim SG函数(多校)
    hdu 5793 A Boring Question 推公式(多校)
  • 原文地址:https://www.cnblogs.com/XiaoVsun/p/13100063.html
Copyright © 2011-2022 走看看