题目描述
一个餐厅在相继的 n nn 天里,每天需用的餐巾数不尽相同。假设第 i ii 天需要 ri r_iri 块餐巾。
餐厅可以购买新的餐巾,每块餐巾的费用为 P PP 分;或者把旧餐巾送到快洗部,洗一块需 M MM 天,
其费用为 F FF 分;或者送到慢洗部,洗一块需 N NN 天,其费用为 S SS 分(S<F S < FS<F)。
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,
以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
试设计一个算法为餐厅合理地安排好 n nn 天中餐巾使用计划,使总的花费最小。
输入格式
第 1 11 行有 6 66 个正整数 n nn、P PP、M MM、F FF、N NN、S SS。
n nn 是要安排餐巾使用计划的天数,P PP 是每块新餐巾的费用,M MM 是快洗部洗一块餐巾需用天数,F F
F 是快洗部洗一块餐巾需要的费用,N NN 是慢洗部洗一块餐巾需用天数,S SS 是慢洗部洗一块餐巾需要的费用。
接下来的 n nn 行是餐厅在相继的 n nn 天里,每天需用的餐巾数。
输出格式
输出餐厅在相继的 n nn 天里使用餐巾的最小总花费。
样例
样例输入
3 10 2 3 3 2
5
6
7
样例输出
145
按照题目描述:每个点拆成两个,会有两个集合 a和b。
1 每天需要x[i]条毛巾,s->ai容量为x[i]费用为0,bi->t容量为x[i]费用为0。
2 毛巾留给下一天 ai->ai+1 容量为INF费用为0.
3 毛巾送去快洗部 ai->bi+f1 容量为INF费用为f2.
4 毛巾送去慢洗部 ai->bi+p2 容量为INF费用位p2
跑最小费用最大流。
#include<stdio.h> #include<algorithm> #include<string.h> #include<queue> using namespace std; const int maxm = 10005; const int maxn = 1000005; const int INF = 1e9 + 7; struct node { int u, v, flow, cost, next; }edge[maxn]; int dis[maxm], pre[maxm], head[maxm]; int n, m, s, t, cnt, val; void init() { cnt = 0, s = 0, t = n * 2 + 1; memset(head, -1, sizeof(head)); } void add(int u, int v, int w, int cost) { edge[cnt].u = u, edge[cnt].v = v; edge[cnt].flow = w, edge[cnt].cost = cost; edge[cnt].next = head[u], head[u] = cnt++; edge[cnt].u = v, edge[cnt].v = u; edge[cnt].flow = 0, edge[cnt].cost = -cost; edge[cnt].next = head[v], head[v] = cnt++; } int bfs() { queue<int>q; for (int i = s;i <= t;i++) dis[i] = INF; memset(pre, -1, sizeof(pre)); dis[s] = 0;q.push(s); while (!q.empty()) { int u = q.front();q.pop(); //printf("%d\n", u); for (int i = head[u];i != -1;i = edge[i].next) { int v = edge[i].v; //printf("%d\n", v); if (dis[v] > dis[u] + edge[i].cost && edge[i].flow) { dis[v] = dis[u] + edge[i].cost; pre[v] = i; q.push(v); } } } if (dis[t] == INF) return 0; //printf("%d\n", dis[t]); return 1; } int MCMF() { int minflow, ans = 0; while (bfs()) { minflow = INF; for (int i = pre[t];i != -1;i = pre[edge[i].u]) minflow = min(minflow, edge[i].flow); //printf("%d\n", minflow); for (int i = pre[t];i != -1;i = pre[edge[i].u]) { edge[i].flow -= minflow; edge[i ^ 1].flow += minflow; } ans += dis[t] * minflow; } return ans; } int main() { int i, j, k, sum, a, b, c, d; scanf("%d%d%d%d%d%d", &n, &val, &a, &b, &c, &d); init(); for (i = 1;i <= n;i++) { scanf("%d", &k); add(s, i, k, 0); add(i + n, t, k, 0); add(s, i + n, INF, val); if (i + 1 <= n) add(i, i + 1, INF, 0); if (i + a <= n) add(i, i + a + n, INF, b); if (i + c <= n) add(i, i + c + n, INF, d); } printf("%d\n", MCMF()); return 0; }