码迷,mamicode.com
首页 > 其他好文 > 详细

【费用流+正负费用处理】UVA11613 Acme Corporation

时间:2020-11-13 12:49:12      阅读:6      评论:0      收藏:0      [点我收藏+]

标签:停止   span   uva   用处   最大   思路   相同   ret   problem   

UVA11613 Acme Corporation

思路

对于第\(i\)个月,货物来源有:当月生产(从源点流入),以及之前的月份流入。因为有保质期,这意味着第\(i-1\)个月留下来的货物里保质期会各不相同,可能其中一部分是第\(i\)个月就过期无法卖出的,这一部分货物显然不能流入第\(i\)个月。

如何连边才能体现“在保质期内卖出”?这就需要将一个月份的流入和流出分别处理,也就是拆成入点\(i\)和出点\(i+n\)。这样,假设在第\(i\)个月生产的货物保质期为\(keep[i]\),那么它就可以在第\(i\)\(i+1\)\(i+2\),...,\(i+keep[i]\)月卖出,具体建边就是\(i→i+n\)\(i→i+1+n\)\(i→i+2+n\),...,\(i→i+keep[i]+n\)。这样,网络内部建边就完成了。

由于费用有正有负(生产成本和盈利),比板子多设一个条件if(dis[t]≥0) return 0; ,即当费用为正时停止增广。最后答案(求的是盈利)再取一次负即可。

void addf(int u, int v, LL w, LL c) {
    //费用流建图
    e[++cnt_e].next = head[u]; e[cnt_e].from = u; e[cnt_e].to = v; e[cnt_e].w = w; e[cnt_e].cost = c; head[u] = cnt_e;
    e[++cnt_e].next = head[v]; e[cnt_e].from = v; e[cnt_e].to = u; e[cnt_e].w = 0; e[cnt_e].cost = -c; head[v] = cnt_e;
}

bool spfa() {
    queue<int> q;
    mem(dis, INF);
    mem(d, 0);
    mem(inq, 0);
    q.push(s); dis[s] = 0; inq[s] = 1;
    d[s] = INF;
    while (!q.empty()) {
        int u = q.front();
        inq[u] = 0; q.pop();
        for (int i = head[u]; i; i = e[i].next) {
            if (e[i].w <= 0) continue;
            int v = e[i].to;
            if (dis[u] + e[i].cost < dis[v]) {
                dis[v] = dis[u] + e[i].cost;
                //费用最短路
                pre[v] = i;
                d[v] = min(d[u], e[i].w);
                //维护路径上的最小残量
                if (!inq[v]) {
                    inq[v] = 1;
                    q.push(v);
                }
            }
        }
    }
    if (dis[t] >= 0) return 0;
    //费用为正时停止增广
    if (!d[t]) return 0;
    return 1;
}

void MCMF() {
    while (spfa()) {
        for (int x = t; x != s; x = e[pre[x] ^ 1].to) {
            e[pre[x]].w -= d[t];
            e[pre[x] ^ 1].w += d[t];
        }
        maxflow += d[t];
        mincost += d[t] * dis[t];
        //流量乘上最小单位流量费用即总流量费用
    }
}

int main() {
    ios::sync_with_stdio(false);
    int kase; cin >> kase; for(int kk=1;kk<=kase;kk++) {
        maxflow = mincost = 0;
        mem(e, 0);
        mem(head, 0);
        mem(pre, 0);
        cnt_e = 1;

        int cost;
        //1个月cost元
        cin >> n >> cost;
        s = n * 2 + 1; t = n * 2 + 2;
        for (int i = 1; i <= n; i++) {
            int a, b, c, d;
            cin >> a >> b >> c >> d >> keep[i];
            //生产成本,最大生产量,售价,最大销售量
            addf(s, i, b, a);
            for (int j = i; j <= min(n, i + keep[i]); j++) {
                addf(i, n + j, b, (j - i) * cost);
            }
            addf(i + n, t, d, -c);
        }
        MCMF();
        cout << "Case " << kk << ": " << -mincost << endl;
    }
    return 0;
}

【费用流+正负费用处理】UVA11613 Acme Corporation

标签:停止   span   uva   用处   最大   思路   相同   ret   problem   

原文地址:https://www.cnblogs.com/streamazure/p/13915862.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!