zoukankan      html  css  js  c++  java
  • 网络流24题- 餐巾计划 (最小费用最大流)

    题意:

    一个餐厅在相继的 n 天里,每天需用的餐巾数不尽相同。假设第 i 天需要 ri块餐巾。餐厅可以购买新的餐巾,每块餐巾的费用为P,

    或者把旧餐巾送到快洗部,洗一块需 M 天,其费用为 F 分;或者送到慢洗部,洗一块需 N ,其费用为 S 分(S<F)。

    每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。

    试设计一个算法为餐厅合理地安排好 n 天中餐巾使用计划,使总的花费最小。编程找出一个最佳餐巾使用计划。

    链接:  https://loj.ac/problem/6008

    输入:

    第1行有6个整数,n,P,M,F,S,N,含义与上面相对应,

    接下来的n行是每天需要的餐巾数

    输出格式:

    将餐厅在相继的 n 天里使用餐巾的最小总花费输出。

    思路:

    建图方式:

    将 i 点拆成 i1 和 i2 ,其中 i1 代表每天的餐巾数,i2 代表每天可以得到的餐巾。

    将源点 S 与 i1 相连,容量为所需要的餐巾数,费用为0,将 i2 与汇点 T 相连,容量为所需要的餐巾数,费用为0

    由于每天可以购买新的餐巾,费用为P,所以将 S 与 i2 相连,容量为INF,费用为P

    用掉的脏餐巾可以累积,所以对于每个 i1 < n ,连接 i1-1 与 i1 ,容量为INF,费用为0

    每天得到的餐巾可以由快洗或者慢洗得到,所以将每个 i1 与若干天后他能清洗完送达到的那个 i2 相连,容量为INF,费用为快洗或慢洗所需的费用

    然后再跑一遍最小费用最大流

    代码:

    写法1:快点

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <queue>
    using namespace std;
    const int MAXN = 2e5 + 5;
    const int INF = 0x7fffffff;
    typedef long long ll;
    int head[MAXN], tot, s, t, n;
    struct node
    {
        int to, nxt, flow, cost;
    } e[MAXN];
    void add(int x, int y, int z, int c)
    {
        e[tot].to = y;
        e[tot].nxt = head[x];
        e[tot].flow = z;
        e[tot].cost = c;
        head[x] = tot++;
    }
    void add_edge(int x, int y, int z, int c)
    {
        add(x, y, z, c);
        add(y, x, 0, -c);
    }
    int dis[MAXN];
    bool visit[MAXN];
    int cost = 0;
    bool spfa()
    {
        queue<int> q;
        memset(visit, 0, sizeof(visit));
        for (int i = 0; i <= 2 * n + 1; i++)
            dis[i] = INF;
        dis[s] = 0;
        q.push(s);
        while (q.size())
        {
            int u = q.front();
            q.pop();
            visit[u] = 0;
            for (int i = head[u]; ~i; i = e[i].nxt)
            {
                int v = e[i].to;
                if (dis[v] > dis[u] + e[i].cost && e[i].flow)
                {
                    dis[v] = dis[u] + e[i].cost;
                    if (!visit[v])
                    {
                        q.push(v);
                        visit[v] = 1;
                    }
                }
            }
        }
        return dis[t] != INF;
    }
    int dfs(int u, int flow)
    {
        if (u == t)
        {
            visit[t] = 1;
            return flow;
        }
        int f = 0;
        visit[u] = 1;
        for (int i = head[u]; ~i; i = e[i].nxt)
        {
            int v = e[i].to;
            if ((!visit[v] || v == t) && e[i].flow && dis[v] == dis[u] + e[i].cost)
            {
                int d = dfs(v, min(flow - f, e[i].flow));
                if (d)
                {
                    cost += e[i].cost * d;
                    e[i].flow -= d;
                    e[i ^ 1].flow += d;
                    f += d;
                    if (f == flow)
                        break;
                }
            }
        }
        return f;
    }
    void mcmf()
    {
        while (spfa())
        {
            // printf("*");
            visit[t] = 1;
            while (visit[t])
            {
                memset(visit, 0, sizeof(visit));
                dfs(s, INF);
            }
        }
    }
    int main()
    {
        int p, f_m, f_p, s_n, s_p;
        scanf("%d%d%d%d%d%d", &n, &p, &f_m, &f_p, &s_n, &s_p);
        memset(head, -1, sizeof(head));
        s = 0, t = 2 * n + 1;
        for (int i = 1; i <= n; i++)
        {
            int need;
            scanf("%d", &need);
            add_edge(s, i, need, 0);
            add_edge(i + n, t, need, 0);
        }
        for (int i = 1; i <= n; i++)
        {
            add_edge(s, i + n, INF, p);
        }
        for (int i = 1; i < n; i++)
            add_edge(i, i + 1, INF, 0);
        for (int i = 1; i + f_m <= n; i++)
            add_edge(i, i + f_m + n, INF, f_p);
        for (int i = 1; i + s_n <= n; i++)
            add_edge(i, i + n + s_n, INF, s_p);
        mcmf();
        printf("%d
    ", cost);
        return 0;
    }
    View Code

    写法2:慢点

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <queue>
    using namespace std;
    const int MAXN = 2e5 + 5;
    const int INF = 0x7fffffff;
    typedef long long ll;
    int head[MAXN], tot, s, t, n, a[200][200];
    struct node {
        int to, nxt, flow, cost;
    } e[MAXN];
    void add(int x, int y, int z, int c) {
        e[tot].to = y;
        e[tot].nxt = head[x];
        e[tot].flow = z;
        e[tot].cost = c;
        head[x] = tot++;
    }
    void add_edge(int x, int y, int z, int c) {
        add(x, y, z, c);
        add(y, x, 0, -c);
    }
    int dis[MAXN], q[MAXN], l, r, pre[MAXN], path[MAXN], visit[MAXN];
    bool spfa() {
        for (int i = 0; i <= 2 * n + 1; i++) dis[i] = INF;
        for (int i = 0; i <= 2 * n + 1; i++) pre[i] = -1;
        l = 0, r = 0;
        dis[s] = 0;
        q[++r] = s;
        while (l != r) {
            int u = q[++l];
            for (int i = head[u]; ~i; i = e[i].nxt) {
                int v = e[i].to;
                if (e[i].flow && dis[u] + e[i].cost < dis[v]) {
                    dis[v] = dis[u] + e[i].cost;
                    pre[v] = u, path[v] = i;
                    if (!visit[v])
                        q[++r] = v, visit[v] = 1;
                }
            }
            visit[u] = 0;
        }
        if (pre[t] == -1)
            return false;
        return true;
    }
    int mcmf() {
        int f = 0, cost = 0;
        while (spfa()) {
            int min_f = INF;
            for (int i = t; i != s; i = pre[i]) {
                if (e[path[i]].flow < min_f)
                    min_f = e[path[i]].flow;
            }
            f += min_f;
            cost += dis[t] * min_f;
            for (int i = t; i != s; i = pre[i]) {
                e[path[i]].flow -= min_f;
                e[path[i] ^ 1].flow += min_f;
            }
        }
        return cost;
    }
    int main() {
        int p, f_m, f_p, s_n, s_p;
        scanf("%d%d%d%d%d%d", &n, &p, &f_m, &f_p, &s_n, &s_p);
        memset(head, -1, sizeof(head));
        s = 0, t = 2 * n + 1;
        for (int i = 1; i <= n; i++) {
            int need;
            scanf("%d", &need);
            add_edge(s, i, need, 0);
            add_edge(i + n, t, need, 0);
        }
        for (int i = 1; i <= n; i++) {
            add_edge(s, i + n, INF, p);
        }
        for (int i = 1; i < n; i++) add_edge(i, i + 1, INF, 0);
        for (int i = 1; i + f_m <= n; i++) add_edge(i, i + f_m + n, INF, f_p);
        for (int i = 1; i + s_n <= n; i++) add_edge(i, i + n + s_n, INF, s_p);
        printf("%d
    ", mcmf());
        return 0;
    }
    View Code
  • 相关阅读:
    Linux设置静态IP
    jenkins+findbugs
    CentOS 6.6 安装 Node.js
    未来物联网、人工智能无法迈过的技术是什么
    未来物联网、人工智能无法迈过的技术是什么
    spss-数据清洗-处理重复数据
    spss-数据清洗-处理重复数据
    大数据时代数据管理方式研究
    大数据时代数据管理方式研究
    Excel表格文本格式的数字和数字格式如何批量转换
  • 原文地址:https://www.cnblogs.com/ljxdtc666/p/12401975.html
Copyright © 2011-2022 走看看