题解 P2517 【[HAOI2010]订货】

Desprition

题目链接

很快啊,一下子就判断出是个费用流。

Solution

首先,构建两个虚拟源汇点。

根据题目分析,

第i个月对某产品的需求量为Ui

结合全文,因为该月可以有剩余,所以不能确定入流限制,那就换条路,咱们选择跟汇点连边。自然而然,容量为 \(Ui\), 费用为 \(0\)(汇点是虚拟的,不需要花费)。

然后我们在从源点向该点连边,因为汇点直接限制了流量,所以容量直接搞成 \(inf\) 就好了,费用为 \(0\)

也就是,当月购进的与源点连边,当月售出的与汇点连边

又因为上一月的剩余可以留到当月处理,但费用为 \(m\)。用小脑袋瓜想想,不就是将上一月向当月连一条边嘛?容量为 \(S\)(仓库容量),费用为 \(m\)

这不就出来了吗,最后跑一遍费用流模板。

Code

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define rt register int
#define int long long
const int N = 105, M = 500, inf = 1e9;
int n, m, V, ff, tot, cnt, S, T, ss, tt;
int head[N], to[M], f[M], w[M], nex[M], q[N], d[N], pre[N], incf[N], v[N];
bool vis[N];
char s;
inline void add(int a, int b, int c, int d) {
    to[tot] = b, f[tot] = c, w[tot] = d, nex[tot] = head[a], head[a] = tot ++;
    to[tot] = a, f[tot] = 0, w[tot] = -d, nex[tot] = head[b], head[b] = tot ++;
}
inline bool spfa() {
    memset(d, 0x3f, sizeof(d) );
    memset(incf, 0, sizeof(incf) );
    ss = 0, tt = 1, q[0] = S, d[S] = 0, incf[S] = inf;
    int now, ver;
    while (ss != tt) {
        now = q[ss ++], vis[now] = 0;
        if(ss == N) ss = 0;
        for(rt i = head[now]; ~i; i = nex[i]) {
            ver = to[i];
            if(f[i] && d[now] + w[i] < d[ver]) {
                d[ver] = d[now] + w[i], pre[ver] = i, incf[ver] = min(f[i], incf[now]);
                if (!vis[ver]) {
                    q[tt ++ ] = ver, vis[ver] = 1;
                    if (tt == N) tt = 0;
                }
            }
        }
    }
    return incf[T] > 0;
}
inline int solve() {
    int cost = 0;
	int now;
    while(spfa()) {
        now = incf[T], cost += now * d[T];
        for(rt i = T; i != S; i = to[pre[i] ^ 1])
            f[pre[i]] -= now, f[pre[i] ^ 1] += now;
    }
    return cost;
}
inline void read(int &x) {
	x = 0, ff = 1, s = getchar();
	while(s < '0' || s > '9') {if(s == '-') ff = -1; s = getchar();}
	while(s <= '9' && s >= '0') {x = x * 10 + s - '0'; s = getchar();}
	x *= ff;
}
signed main() {
	memset(head,-1,sizeof(head));
	read(n), read(m), read(V);
	int x;
	S = n + 1,T = S + 1; 
	for(rt i = 1; i <= n; i ++) {
		read(v[i]);
		add(i,T,v[i],0);
	}
	for(rt i = 1; i <= n; i ++) {
		read(x);
		add(S,i,inf,x);
		if(i < n) add(i,i + 1,V,m);
	}
	printf("%lld",solve());
	return 0;
} 
posted @ 2021-01-14 22:05  Spring-Araki  阅读(122)  评论(0)    收藏  举报