洛谷 P1251 餐巾计划问题 (费用流)网络流24题(3)
链接
题意:有一个餐厅,每天需要一定数量的餐巾
x
[
i
]
x[i]
x[i],每天可以购买餐巾,花费
p
p
p,或者送清洗店,花费
d
a
y
1
day_1
day1,
c
o
s
t
1
cost_1
cost1或者
d
a
y
2
day_2
day2,
c
o
s
t
2
cost_2
cost2,除了
x
x
x,对于每一天其他变量都是一样的
思路:我们考虑把每一天拆点,分成早上和晚上,记早上是
i
i
i,晚上是
i
′
i'
i′
1.对于每一天,我们可以购买,所以直接连接
s
→
i
(
I
N
F
,
p
)
s\to i (INF,p)
s→i(INF,p),代表购买
2.因为每一天需要使用
x
[
i
]
x[i]
x[i],所以我们还需要连接每一天到汇点,由于晚上的毛巾代表的是脏毛巾,所以我们要连接的是
i
→
t
(
x
[
i
]
,
0
)
i\to t(x[i],0)
i→t(x[i],0)
3.因为每天会产生
x
[
i
]
x[i]
x[i]的脏毛巾,我们感性考虑应该是从
i
→
i
′
(
x
[
i
]
,
0
)
i\to i'(x[i],0)
i→i′(x[i],0),但是这是不对的,因为这样一来我们就需要每天有
2
∗
x
[
i
]
2*x[i]
2∗x[i]的毛巾才能满足到汇点和到
i
′
i'
i′的流量,所以我们直接
s
→
i
′
(
x
[
i
]
,
0
)
s\to i'(x[i],0)
s→i′(x[i],0)
4.每一天,我们可以送至两个洗衣店,所以我们可以把每天晚上脏毛巾送至
i
+
d
a
y
1
/
2
i+day_{1/2}
i+day1/2的干净毛巾,有
i
′
→
i
+
d
a
y
1
/
2
(
I
N
F
,
c
o
s
t
1
/
2
)
i'\to i+day_{1/2}(INF,cost_{1/2})
i′→i+day1/2(INF,cost1/2)
5.我们可以累计毛巾,所以我们选择留脏毛巾,或者干净毛巾,效果是一样的,因为每天购买的价格一样,我选择留脏毛巾,有
i
′
→
(
i
+
1
)
′
(
I
N
F
,
0
)
i'\to (i+1)'(INF,0)
i′→(i+1)′(INF,0)
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 4e3+15, INF = 0x3f3f3f3f3f3f3f3f;
int head[N], idx = 1;
struct Edge{int to, nxt, d, c;}e[10000010];
void add(int u, int v, int d, int c)
{
e[++idx].to = v, e[idx].nxt = head[u], head[u] = idx, e[idx].d = d, e[idx].c = c;
e[++idx].to = u, e[idx].nxt = head[v], head[v] = idx, e[idx].d = 0, e[idx].c = -c;
}
int n, p, m, f, n1, s1;
int dis[N], inq[N], incf[N], pre[N], s, t, maxflow, mincost;
bool spfa()
{
queue<int> Q;
memset(dis, 0x3f, sizeof (dis));
memset(inq, 0, sizeof (inq));
Q.push(s);
dis[s] = 0;
inq[s] = 1;
incf[s] = INF;
while (!Q.empty()) {
int u = Q.front(); Q.pop();
inq[u] = 0;
for (int i = head[u]; i; i = e[i].nxt) {
if (!e[i].d) continue;
int v = e[i].to, d = e[i].c;
if (dis[v] > dis[u] + d) {
dis[v] = dis[u] + d;
incf[v] = min(incf[u], e[i].d);
pre[v] = i;
if (!inq[v]) {inq[v] = 1; Q.push(v);}
}
}
}
return dis[t] != 0x3f3f3f3f3f3f3f3f;
}
int MCMF()
{
while (spfa()) {
int x = t;
maxflow += incf[t];
mincost += dis[t] * incf[t];
int i;
while (x != s) {
i = pre[x];
e[i].d -= incf[t];
e[i ^ 1].d += incf[t];
x = e[i ^ 1].to;
}
}return mincost;
}
signed main()
{
cin >> n;
t = n + n + 10;
for (int i = 1; i <= n; i++) {
int x; cin >> x;
add(i, t, x, 0);
add(s, i + n, x, 0);
}
cin >> p >> m >> f >> n1 >> s1;
for (int i = 1; i <= n; i++) {
add(s, i, INF, p);
if (i != n) add(i + n, i + 1 + n, INF, 0);
if (i + m <= n) add(i + n, i + m, INF, f);
if (i + n1 <= n) add(i + n, i + n1, INF, s1);
}
cout << MCMF();
return 0;
}