[NOI 2012] 美食节

[题目链接]

         https://www.lydsy.com/JudgeOnline/problem.php?id=2879

[算法]

        首先 , 将每种食物建一个点 , 将每位厨师做的每一道菜建一个点

        建图如下 :

              1. 将原点与每种食物连一条流量为Ai , 费用为0的边

              2. 将每种食物像每位厨师的每道菜连一条流量为1 , 费用为Ti,j * k的边(其中 , i表示第i种食物 , j表示第j位厨师 , k表示该厨师做的倒数第k道菜)

              3. 将每位厨师做的每道菜向汇点连一条流量为1 , 费用为0的边

        在这张图上跑最小费用最大流即为答案

        由于边太多 , 我们需要动态加边 , 否则将无法在时限内通过此题

        时间复杂度 : O(Costflow(NM + P , NMP))

[代码]

        

#include<bits/stdc++.h>
using namespace std;
#define MAXN 80
#define MAXM 110
#define MAXP 1010
const int INF = 2e9;

struct edge
{
        int to , w , cost , nxt;
} e[MAXN * MAXM * MAXP];

int n , m , cnt , tot , ans , S , T;
int a[MAXN] , dist[MAXM * MAXP] , head[MAXM * MAXP] , pre[MAXM * MAXP] , incf[MAXM * MAXP];
int t[MAXN][MAXM];
bool inq[MAXM * MAXP];

template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> inline void read(T &x)
{
    T f = 1; x = 0;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
    for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
    x *= f;
}
inline void addedge(int u , int v , int w , int cost)
{
        ++tot;
        e[tot] = (edge){v , w , cost , head[u]};
        head[u] = tot;
        ++tot;
        e[tot] = (edge){u , 0 , -cost , head[v]};
        head[v] = tot;
}
inline bool spfa()
{
        queue< int > q;
        for (int i = 1; i <= T; i++)
        {
                dist[i] = INF;
                incf[i] = INF;
                inq[i] = false;
                pre[i] = 0;
        }
        q.push(S);
        inq[S] = true;
        dist[S] = 0;
        while (!q.empty())
        {
                int cur = q.front();
                q.pop();
                inq[cur] = false;
                for (int i = head[cur]; i; i = e[i].nxt)
                {
                        int v = e[i].to , w = e[i].w , cost = e[i].cost;
                        if (w > 0 && dist[cur] + cost < dist[v])
                        {
                                dist[v] = dist[cur] + cost;
                                pre[v] = i;
                                incf[v] = min(incf[cur] , w);
                                if (!inq[v])
                                {
                                        q.push(v);
                                        inq[v] = true;
                                }
                        }
                }
         }        
         if (dist[T] < INF) return true;
         else return false;
}
inline void update()
{
        int now = T;
        while (now != S)
        {
                int pos = pre[now];
                e[pos].w -= incf[T];
                e[pos ^ 1].w += incf[T];
                now = e[pos ^ 1].to;
        }
        ans += dist[T] * incf[T];
        int pos = (e[pre[T] ^ 1].to - n - 1) / cnt + 1 , v = (e[pre[T] ^ 1].to - n - 1) % cnt + 1;
        for (int i = 1; i <= n; i++) addedge(i , e[pre[T] ^ 1].to + 1 , 1 , t[i][pos] * (v + 1));
}

int main()
{
        
        read(n); read(m);
        for (int i = 1; i <= n; i++) 
        {
                read(a[i]);
                cnt += a[i];
        }
        for (int i = 1; i <= n; i++)
        {
                for (int j = 1; j <= m; j++)
                {
                        read(t[i][j]);
                }
        }
        tot = 1;
        S = n + m * cnt + 1 , T = S + 1;
        for (int i = 1; i <= n; i++) addedge(S , i , a[i] , 0);
        for (int i = 1; i <= m * cnt; i++) addedge(n + i , T , 1 , 0);
        for (int i = 1; i <= n; i++)
        {    
                for (int j = 1; j <= m; j++)
                {
                        addedge(i , n + (j - 1) * cnt + 1 , 1 , t[i][j]);
                }
        }
        while (spfa()) update();
        printf("%d\n" , ans);
         
        return 0;
    
}

 

posted @ 2018-10-28 21:24  evenbao  阅读(218)  评论(0编辑  收藏  举报