首页 > 代码库 > BZOJ 2879 NOI 2012 美食节 费用流

BZOJ 2879 NOI 2012 美食节 费用流

题目大意:好长,如果不想看可以先看看修车那个题,基本一样。


思路:做过修车就好办了。这个题仅仅是数据范围变大了一坨。建图就不说了,主要是动态加边。倒过来做,因为一个厨师最后一个菜做的时间是不会影响到其他菜的时间的。而且每一个厨师确定了最后一个菜才能去想倒数第二个菜是什么。所以每跑一次SPFA,就回来看看是哪个厨师做的菜,然后在多加一个点限制一下流量,将这个点连向所有的菜。


CODE:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 110
#define MAXP 100010
#define MAXE 200010
#define INF 0x3f3f3f3f
#define S 0
#define T (MAXP - 1)
using namespace std;
 
int cooks,chefs;
int need[MAX];
int src[MAX][MAX],cnt;
 
int now[MAX];
 
struct MinCostMaxFlow{
    int head[MAXP],total;
    int _next[MAXE],aim[MAXE],flow[MAXE],cost[MAXE];
     
    int f[MAXP],from[MAXP],p[MAXP];
    bool v[MAXP];
     
    MinCostMaxFlow() {
        total = 1;
    }
    void Add(int x,int y,int f,int c) {
        _next[++total] = head[x];
        aim[total] = y;
        flow[total] = f;
        cost[total] = c;
        head[x] = total;
    }
    void Insert(int x,int y,int f,int c) {
        Add(x,y,f,c);
        Add(y,x,0,-c);
    }
    void Initialize() {
        for(int i = 1; i <= chefs; ++i) {
            Insert(i,++cnt,1,0);
            for(int j = 1; j <= cooks; ++j)
                Insert(cnt,chefs + j,1,src[j][i]);
        }
    }
    bool SPFA() {
        static queue<int> q;
        while(!q.empty())   q.pop();
        memset(f,0x3f,sizeof(f));
        f[S] = 0;
        q.push(S);
        while(!q.empty()) {
            int x = q.front(); q.pop();
            v[x] = false;
            for(int i = head[x]; i; i = _next[i])
                if(flow[i] && f[aim[i]] > f[x] + cost[i]) {
                    f[aim[i]] = f[x] + cost[i];
                    if(!v[aim[i]]) {
                        v[aim[i]] = true;
                        q.push(aim[i]);
                    }
                    from[aim[i]] = x;
                    p[aim[i]] = i;
                }
        }
        return f[T] != INF;
    }
    int EdmondsKarp() {
        int re = 0;
        while(SPFA()) {
            int remain_flow = INF;
            for(int i = T; i != S; i = from[i])
                remain_flow = min(remain_flow,flow[p[i]]);
            static int k,temp;
            for(int i = T; i != S; i = from[i]) {
                flow[p[i]] -= remain_flow;
                flow[p[i]^1] += remain_flow;
                if(i <= chefs && i >= 1)  k = i;
                if(i != T && i > chefs)      temp = i;
            }
            ++now[k];
            Insert(k,++cnt,1,0);
            for(int i = 1; i <= cooks; ++i)
                Insert(cnt,chefs + i,1,(now[k] + 1) * src[i][k]);
            re += f[T] * remain_flow;
        }
        return re;
    }
}solver;
 
int main()
{
    cin >> cooks >> chefs;
    for(int i = 1; i <= cooks; ++i)
        scanf("%d",&need[i]);
    for(int i = 1; i <= cooks; ++i)
        for(int j = 1; j <= chefs; ++j)
            scanf("%d",&src[i][j]);
     
    for(int i = 1; i <= chefs; ++i)
        solver.Insert(S,++cnt,INF,0);
    int p = 0;
    for(int i = 1; i <= cooks; ++i) {
        solver.Insert(++cnt,T,need[i],0);
        p += need[i];
    }
    solver.Initialize();
    cout << solver.EdmondsKarp() << endl;
    return 0;
}


BZOJ 2879 NOI 2012 美食节 费用流