一个餐厅在相继的 N N 天里,每天需用的餐巾数不尽相同。假设第 i i 天需要 ri r i 块餐巾 (i=1,2,...,N) ( i = 1 , 2 , . . . , N ) 。餐厅可以购买新的餐巾,每块餐巾的费用为 p p 分;或者把旧餐巾送到快洗部,洗一块需 m m 天,其费用为 f f 分;或者送到慢洗部,洗一块需 n n 天( n>m n > m ),其费用为 s s 分( s<f s < f )。
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
试设计一个算法为餐厅合理地安排好 N N 天中餐巾使用计划,使总的花费最小。编程找出一个最佳餐巾使用计划。
由标准输入提供输入数据。文件第 1 1 行有 1 1 个正整数 N N ,代表要安排餐巾使用计划的天数。
接下来的 N N 行是餐厅在相继的 N N 天里,每天需用的餐巾数。
最后一行包含 5 5 个正整数 p,m,f,n,s p , m , f , n , s 。 p p 是每块新餐巾的费用; m m 是快洗部洗一块餐巾需用天数; f f 是快洗部洗一块餐巾需要的费用; n n 是慢洗部洗一块餐巾需用天数; s s 是慢洗部洗一块餐巾需要的费用。
将餐厅在相继的 N N 天里使用餐巾的最小总花费输出
3
1 7 5
11 2 2 3 1
134
N<=2000 N <= 2000
ri<=10000000 r i <= 10000000
p,f,s<=10000 p , f , s <= 10000
费用流的经典模型。
考虑如何建边:我们显然不能像题目所述的一样, 将白天的点又连回晚上的点, 这样就会混淆退流边和表示餐巾清洗的边,并且费用加在哪里不好确定。
因此我们将图建成二分图模型,连以下 6 6 类边:
这样我们一路增广至最大流时即可满足。
代码如下:
#include
#include
#include
#include
#include
#include
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 100050
#define S 50000
#define T 50001
#define INF 999999999
template <class TT>
IN void in(TT &x)
{
x = 0; R char c = gc;
W (!isdigit(c)) c = gc;
W (isdigit(c))
x = (x << 1) + (x << 3) + c - 48, c = gc;
}
struct Edge
{
int to, flow, cost, nex;
}edge[MX << 1];
int slow, fast, day, cnt = -1, nw, fc, sc, hd, tl;
long long ans;
int head[MX], rec[MX], del[MX], que[MX], dis[MX];
bool inq[MX];
IN void add(const int &from, const int &to, const int &cost, const int &fl)
{
edge[++cnt] = {to, fl, cost, head[from]}; head[from] = cnt;
edge[++cnt] = {from, 0, -cost, head[to]}; head[to] = cnt;
}
IN bool SPFA()
{
R int now;
que[tl = hd = 1] = S;
std::memset(dis, 63, sizeof(dis));
del[S] = INF; dis[S] = 0;
W (tl <= hd)
{
now = que[tl++];
for (R int i = head[now]; ~i; i = edge[i].nex)
{
if(edge[i].flow > 0 && dis[edge[i].to] > dis[now] + edge[i].cost)
{
del[edge[i].to] = std::min(edge[i].flow, del[now]);
dis[edge[i].to] = dis[now] + edge[i].cost;
rec[edge[i].to] = i;
if(!inq[edge[i].to]) inq[edge[i].to] = true, que[++hd] = edge[i].to;
}
}
inq[now] = false;
}
return dis[T] < 99999999;
}
IN void updata()
{
ans += del[T] * dis[T];
R int now = T, tar;
W (now != S)
{
tar = rec[now];
edge[tar].flow -= del[T];
edge[tar ^ 1].flow += del[T];
now = edge[tar ^ 1].to;
}
}
long long EK()
{
W (SPFA()) updata();
return ans;
}
int main(void)
{
in(day); int a, b;
std::memset(head, -1, sizeof(head));
for (R int i = 1; i <= day; ++i)
in(a), add(i, T, 0, a), add(S, i + day, 0, a);
in(nw), in(fast), in(fc), in(slow), in(sc);
for (R int i = 1; i <= day; ++i) add(S, i, nw, INF);
for (R int i = 1; i < day; ++i) add(day + i, day + i + 1, 0, INF);
int bd = std::max(0, day - fast);
for (R int i = 1; i <= bd; ++i) add(day + i, i + fast, fc, INF);
bd = std::max(0, day - slow);
for (R int i = 1; i <= bd; ++i) add(day + i, i + slow, sc, INF);
printf("%lld", EK());
}