• [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
    " , ans);
             
            return 0;
        
    }
  • 相关阅读:
    python基础函数补充
    简单有效的科学健脑方法
    欧几里德算法 GCD
    bzoj 2226: [Spoj 5971] LCMSum 数论
    世界语音列表
    2019.08.23【NOIP提高组】模拟 A 组 总结
    数据结构与算法_04 _ 复杂度分析(下):浅析最好、最坏、平均、均摊时间复杂度
    数据结构与算法_03 _ 复杂度分析(上):如何分析、统计算法的执行效率和资源消耗
    数据结构与算法_02 _ 如何抓住重点,系统高效地学习数据结构与算法
    数据结构与算法_01 _ 为什么要学习数据结构和算法?
  • 原文地址:https://www.cnblogs.com/evenbao/p/9867273.html
Copyright © 2020-2023  润新知