题目大意:
某产品第i个月需求量为Ui,订货单价为di。
某
产
品
第
i
个
月
需
求
量
为
U
i
,
订
货
单
价
为
d
i
。
上个月月底未销完的单位产品要付存贮费用m。
上
个
月
月
底
未
销
完
的
单
位
产
品
要
付
存
贮
费
用
m
。
假定第1月月初的库存量为0,第n月月底的库存量也为0。
假
定
第
1
月
月
初
的
库
存
量
为
0
,
第
n
月
月
底
的
库
存
量
也
为
0
。
问如何安排这n个月订购计划,才能使成本最低?
问
如
何
安
排
这
n
个
月
订
购
计
划
,
才
能
使
成
本
最
低
?
每月月初订购,订购后产品立即到货,进库并供应市。
每
月
月
初
订
购
,
订
购
后
产
品
立
即
到
货
,
进
库
并
供
应
市
。
于当月被售掉则不必付存贮费。假设仓库容量为S。
于
当
月
被
售
掉
则
不
必
付
存
贮
费
。
假
设
仓
库
容
量
为
S
。
0<=n<=50,0<=m<=10,0<=S<=10000
0
<=
n
<=
50
,
0
<=
m
<=
10
,
0
<=
S
<=
10000
0<=Ui<=10000
0
<=
U
i
<=
10000
0<=di<=100
0
<=
d
i
<=
100
分析:
动态规划:
设f[i][j]表示到了第i个月底,仓库里存货数量为j时的最低成本。
设
f
[
i
]
[
j
]
表
示
到
了
第
i
个
月
底
,
仓
库
里
存
货
数
量
为
j
时
的
最
低
成
本
。
显然的
f[i][j]=min{f[i−1][k]+k∗m+(u[i]+j−k)∗d[i]}
f
[
i
]
[
j
]
=
m
i
n
{
f
[
i
−
1
]
[
k
]
+
k
∗
m
+
(
u
[
i
]
+
j
−
k
)
∗
d
[
i
]
}
可是这样的话,我们的时间复杂度可能就会达到
O(NS2)
O
(
N
S
2
)
我们发现,斜率优化一下,将
k移项
k
移
项
,
可以得到
f[i][j]=min{f[i−1][k]+(m−d[i])∗k+(u[i]+j)∗d[i]}
f
[
i
]
[
j
]
=
m
i
n
{
f
[
i
−
1
]
[
k
]
+
(
m
−
d
[
i
]
)
∗
k
+
(
u
[
i
]
+
j
)
∗
d
[
i
]
}
那么我们可以同步枚举
j,k
j
,
k
,
时间复杂度就是
O(NS)
O
(
N
S
)
费用流:
连边
S−>i
S
−
>
i
,流量无穷,
单位费用为d[i]
单
位
费
用
为
d
[
i
]
连边
i−>T
i
−
>
T
,流量为
U[i]
U
[
i
]
,
单位费用为0
单
位
费
用
为
0
连边
i−>i+1
i
−
>
i
+
1
,流量为
S
S
,
然后同时建反向边,跑最小费用最大流
代码:
斜率优化dp:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define INF 0x7fffffff
#define M 10005
#define N 55
using namespace std;
int f[N][M], u[N], d[N], n, m, S;
int main() {
scanf("%d %d %d", &n, &m, &S);
for (int i = 1; i <= n; i++) scanf("%d", &u[i]);
for (int i = 1; i <= n; i++) scanf("%d", &d[i]);
for (int i = 0; i <= S; i++)
f[1][i] = (u[1] + i) * d[1];
for (int i = 2; i <= n; i++) {
int k = 0, cmin = INF;
for (int j = 0; j <= S; j++) {
for (; k <= min(u[i] + j, S); k++)
cmin = min(cmin, f[i - 1][k] + (m - d[i]) * k);
f[i][j] = cmin + (u[i] + j) * d[i];
}
}
printf("%d\n", f[n][0]);
return 0;
}
费用流:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define INF 0x7fffffff
#define N 55
using namespace std;
struct edge {
int to, num, cost, nt;
}e[6 * N];
int incf[N], dis[N], pre[N], Ls[N], v[N], n, m, C, S, T, cnt = 1;
int Max_flow = 0, Ans_cost = 0;
void Addedge(int u, int v, int w, int f) {
e[++cnt].to = v, e[cnt].num = w, e[cnt].cost = f, e[cnt].nt = Ls[u], Ls[u] = cnt;
e[++cnt].to = u, e[cnt].num = 0, e[cnt].cost = -f, e[cnt].nt = Ls[v], Ls[v] = cnt;
}
bool spfa(int s, int t) {
for (int i = s; i <= t; i++) dis[i] = INF;
memset(v, 0, sizeof(v));
queue <int> Q;
Q.push(s);
v[s] = 1; dis[s] = 0;
incf[s] = INF;
while (!Q.empty()) {
int u = Q.front();
Q.pop();
for (int i = Ls[u]; i ; i = e[i].nt)
if (e[i].num && dis[e[i].to] > dis[u] + e[i].cost){
dis[e[i].to] = dis[u] + e[i].cost;
incf[e[i].to] = min(incf[u], e[i].num);
pre[e[i].to] = i;
if (!v[e[i].to]) {
Q.push(e[i].to);
v[e[i].to] = 1;
}
}
v[u] = 0;
}
return dis[t] != INF;
}
void update(int s, int t) {
int x = t;
while (x != s) {
int i = pre[x];
e[i].num -= incf[t];
e[i^1].num += incf[t];
x = e[i^1].to;
}
Max_flow += incf[t];
Ans_cost += dis[t] * incf[t];
}
int EK(int s, int t) {
while (spfa(s, t)) update(s, t);
}
int main() {
scanf("%d %d %d", &n, &m, &C);
int x; S = 0, T = n + 1;
for (int i = 1; i <= n; i++) {
scanf("%d", &x);
Addedge(i, T, x, 0);
}
for (int i = 1; i <= n; i++) {
scanf("%d", &x);
Addedge(S, i, INF, x);
}
for (int i = 1; i <= n - 1; i++)
Addedge(i, i + 1, C, m);
EK(S, T);
printf("%d\n", Ans_cost);
return 0;
}