题目描述
申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管。布布刚上任就遇到了一个难题:为即将启动的奥运新项目招募一批短期志愿者。经过估算,这个项目需要N 天才能完成,其中第i 天至少需要Ai 个人。 布布通过了解得知,一共有M 类志愿者可以招募。其中第i 类可以从第Si 天工作到第Ti 天,招募费用是每人Ci 元。新官上任三把火,为了出色地完成自己的工作,布布希望用尽量少的费用招募足够的志愿者,但这并不是他的特长!于是布布找到了你,希望你帮他设计一种最优的招募方案。
输入输出格式
输入格式:
第一行包含两个整数N, M,表示完成项目的天数和可以招募的志愿者的种类。 接下来的一行中包含N 个非负整数,表示每天至少需要的志愿者人数。 接下来的M 行中每行包含三个整数Si, Ti, Ci,含义如上文所述。为了方便起见,我们可以认为每类志愿者的数量都是无限多的。
输出格式:
仅包含一个整数,表示你所设计的最优方案的总费用。
输入输出样例
说明
1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,题目中其他所涉及的数据均 不超过2^31-1。
本题提供了网络流题型中一种模板化的构图技巧。简单来说把等式抽象成点,将等式化为右边为0的形式。这样我们把加看做入度,减看做出度,等式的性质便是网络流中的流量平衡。详细可以看这篇博客:我是"这篇博客"
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define S 0 #define T (n + 3) using namespace std; const int maxn = 1e4 + 5, inf = 0x3f3f3f3f; struct edge { int v, w, flow, next; }e[maxn << 3]; int head[maxn], cnt, n, m, p[maxn], a, b, c; void adde(const int &u, const int &v, const int &w, const int &flow) { e[cnt] = (edge) {v, w, flow, head[u]}; head[u] = cnt++; e[cnt] = (edge) {u, -w, 0, head[v]}; head[v] = cnt++; } int dis[maxn], pre[maxn][2], vis[maxn]; int SPFA(int s, int t) { queue<int > q; q.push(s), memset(dis, 0x3f, sizeof(dis)); memset(vis, 0, sizeof(vis)), vis[s] = 1, dis[s] = 0; while(!q.empty()) { int u = q.front(); q.pop(), vis[u] = 0; for(register int i = head[u]; ~i; i = e[i].next) { if(!e[i].flow) continue; int v = e[i].v; if(dis[v] > dis[u] + e[i].w) { dis[v] = dis[u] + e[i].w; pre[v][1] = i, pre[v][0] = u; if(!vis[v]) q.push(v), vis[v] = 1; } } } return dis[t]; } int Flow(int s, int t, int f) { if(s == t) return f; int i = pre[s][1], ret = Flow(pre[s][0], t, min(e[i].flow, f)); return e[i].flow -= ret, e[i ^ 1].flow += ret, ret; } int MinFlow(int s, int t) { int ans = 0, ret = inf; while(1) { ret = SPFA(s, t); if(ret == inf) break; ans += ret * Flow(t, s, inf); } return ans; } int main() { memset(head, -1, sizeof(head)); scanf("%d%d", &n, &m); for(register int i = 1; i <= n; ++i) { scanf("%d", &p[i]), adde(i + 1, i, 0, inf); } for(register int i = 1; i <= m; ++i) { scanf("%d%d%d", &a, &b, &c); adde(a, b + 1, c, inf); } for(register int i = 1; i <= n + 1; ++i) { if(p[i] - p[i - 1] > 0) adde(S, i, 0, p[i] - p[i - 1]); if(p[i] - p[i - 1] < 0) adde(i, T, 0, p[i - 1] - p[i]); } printf("%d", MinFlow(S, T)); return 0; }
没有帐号? 立即注册