题意:最多1000天 每天需要至少ai个工人施工 有10000种工人可以雇佣
每种工人可以工作si到ti天 雇佣一个的花费是ci 问怎样安排使得施工花费最少
思考:最直白的建模方式 就是每种工人可以和他能工作的天 连边
但是这样就引出了一个一对多的问题 一种工人对他所连的所有天 贡献是一样的
也就是说他流向和他连的天的 流量应该都是一样的 但是网络流显然是做不到这一点
于是我们重新思考 发现每种工人其实就是一种区间覆盖 那么我们考虑差分的思想
把每相邻两天连起来 表示这种工人在第i天工作了后 跑到第i+1天去工作了
因为每种工人最多工作到ti天 所以我们要考虑某种方式在ti+1天把si流进来的流量放出去 他不能对ti+1天有贡献
然后就不会了....
题解:把每一天当作点 今天向明天连一条 容量INF-ai 花费0的边
对于每种工人 从si天向ti+1天 连 容量为INF 花费为ci的边
s连1 容量INF花费0 n+1连t 容量INF 花费0
跑一遍最大流 因为一定有完成施工的方案 所以能满流 得到的最小花费就是答案
为什么每两天之间的容量是INF-ai 表示今天需要至少ai的流量从带权边补足到INF

#include <bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; int n, m, cnt, mincost, s, t; struct node { int to, nex, val, cost; }E[30005]; int head[1005]; int cur[1005]; int a[1005]; void addedge(int x, int y, int va, int cos) { E[++cnt].to = y; E[cnt].nex = head[x]; head[x] = cnt; E[cnt].val = va; E[cnt].cost = cos; E[++cnt].to = x; E[cnt].nex = head[y]; head[y] = cnt; E[cnt].val = 0; E[cnt].cost = -cos; } int dis[1005], inque[1005], vis[1015]; bool spfa() { for(int i = 1; i <= t; i++) dis[i] = INF, inque[i] = 0, cur[i] = head[i]; queue<int> que; que.push(s); dis[s] = 0; inque[s] = 1; while(!que.empty()) { int u = que.front(); que.pop(); inque[u] = 0; for(int i = head[u]; i; i = E[i].nex) { int v = E[i].to; if(E[i].val && dis[v] > dis[u] + E[i].cost) { dis[v] = dis[u] + E[i].cost; if(!inque[v]) { inque[v] = 1; que.push(v); } } } } return dis[t] != INF; } int dfs(int x, int flow) { if(x == t) { vis[t] = 1; return flow; } vis[x] = 1; int used = 0, rflow = 0; for(int i = cur[x]; i; i = E[i].nex) { cur[x] = i; int v = E[i].to; if(E[i].val && dis[v] == dis[x] + E[i].cost && (!vis[v] || v == t)) { if(rflow = dfs(v, min(E[i].val, flow - used))) { used += rflow; E[i].val -= rflow; E[i ^ 1].val += rflow; mincost += rflow * E[i].cost; if(used == flow) break; } } } return used; } void dinic() { mincost = 0; while(spfa()) { vis[t] = 1; while(vis[t]) { memset(vis, 0, sizeof(int) * (t + 1)); dfs(s, INF); } } } int main() { cnt = 1; scanf("%d%d", &n, &m); s = n + 2; t = s + 1; for(int i = 1; i <= n; i++) scanf("%d", &a[i]); for(int i = 1; i <= m; i++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); addedge(a, b + 1, INF, c); } for(int i = 1; i <= n; i++) addedge(i, i + 1, INF - a[i], 0); addedge(s, 1, INF, 0); addedge(n + 1, t, INF, 0); dinic(); printf("%d ", mincost); return 0; }