[网络流24题] 餐巾计划问题 最小费用最大流

还是 d y x P P T 上的题, 这道题实际上根据描述来建图还是不难的, 但是我费用流模板打得好像太suo了所以一直 T L E , 最后还是贴的自己板子, 看来还是要把基础模板再总结一遍 o v o
首先由于每个点有两个信息, 干净餐巾和脏餐巾, 那么我们把每个点拆成两个 x 1 , y 1 分别存储这两个信息。首先每天可以购买新餐巾, 那么就从 S 向每一个 x 1 连一条流量为 i n f , 费用为新餐巾价格的边, 每天需要 X 条餐巾, 那么就从每个 x 1 T 连流量为 X , 费用为 0 的边, 每天的干净餐巾用完后就变脏了, 那么就可以从 S 向每一个 y 1 连一条流量为 X , 费用为 0 的边, 每天的脏餐巾可以留到第二天, 所以每个 y 1 可以向下一天的 y 1 连一条流量为 i n f , 费用为 0 的边, 最后快洗和慢洗就从每天的 y 1 向洗完后那天的 x 1 连流量为 i n f , 费用为快洗或慢洗价格的边, 这样这个图就建完了。
正确性证明:首先每个点一定是可以每天都购买新餐巾的, 那么满流这个条件一定可以满足, 所以我们直接在最大流的基础上求解最小费用就ok了。
题目链接

Codes

#include<bits/stdc++.h>
#define For(i, a, b) for(register int i = a; i <= b; ++ i)
#define go(x, i) for(register int i = head[x]; i; i = nxt[i])
#define int long long

using namespace std;
const int maxn = 2000 + 10, maxm = 5e5 + 10;
int n, p, qv, qd, sv, sd, Day[maxn], S, T;

template<class T>inline bool chkmin(T &_, T __) {
    return _ > __ ? _ = __, 1 : 0;
}

namespace Mincost_Maxflow {
    int to[maxm], head[maxm], w[maxm], v[maxm], nxt[maxm], e = 1;
    int dis[maxm], vis[maxm], Cost;

    inline void add(int x, int y, int z, int val) {
        to[++ e] = y;
        nxt[e] = head[x];
        head[x] = e;
        w[e] = z;
        v[e] = val;
        if(z) add(y, x, 0, -val);
    }

    inline bool SPFA() {
        queue<int> q;
        For(i, 1, n * 2 + 2) vis[i] = 0, dis[i] = 1e18;
        q.push(vis[S] = S), dis[S] = 0;
        while(!q.empty()) {
            int k = q.front(); q.pop();
            go(k, i) 
                if(w[i] && chkmin(dis[to[i]], dis[k] + v[i]) && !vis[to[i]])
                    q.push(vis[to[i]] = to[i]);
            vis[k] = false;
        }
        return dis[T] < 1e18;
    }

    inline int dfs(int x, int flow) {
        if(x == T || !flow) 
            return vis[x] = flow;
        int used = 0; vis[x] = true;
        go(x, i) 
            if(dis[to[i]] == dis[x] + v[i] && !vis[to[i]]) {
                int di = dfs(to[i], min(flow, w[i]));
                w[i] -= di, w[i ^ 1] += di;
                used += di, flow -= di; Cost += di * v[i];
                if(!flow) break;
            }
        return used;
    }

     inline int Flow() {
        int res = 0;
        while(SPFA()) {
            vis[T] = true;
            while(vis[T]) {
                For(i, 1, n * 2 + 2)
                    vis[i] = 0;
                res += dfs(S, 1e18);
            }
        }
        return res;
     }
}

main() {
#ifndef ONLINE_JUDGE
    freopen("1251.in", "r", stdin);
    freopen("1251.out", "w", stdout);
#endif
    scanf("%lld", &n);
    For(i, 1, n) scanf("%lld", &Day[i]);
    scanf("%lld%lld%lld%lld%lld", &p, &qd, &qv, &sd, &sv);
    S = 1, T = (n << 1) + 2;
    For(i, 1, n) {
        Mincost_Maxflow::add(S, i << 1, 1e18, p);
        Mincost_Maxflow::add(i << 1, T, Day[i], 0);
        Mincost_Maxflow::add(S, i << 1 | 1, Day[i], 0);     
        if(i + 1 <= n) Mincost_Maxflow::add(i << 1 | 1, (i + 1) << 1 | 1, 1e18, 0);
        if(i + qd <= n) Mincost_Maxflow::add(i << 1 | 1, (i + qd) << 1, 1e18, qv);
        if(i + sd <= n) Mincost_Maxflow::add(i << 1 | 1, (i + sd) << 1, 1e18, sv);
    }
    Mincost_Maxflow::Flow();
    printf("%lld\n", Mincost_Maxflow::Cost);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lunch__/article/details/81279145
今日推荐