费用流
比较裸的费用流,唯一的问题在于费用,由于费用是单调递增的,那么我们可以拆边,源点连向每个人source->i,f=ti-ti-1,c=w,这样就好了,因为费用递增,所以符合费用流的贪心思想,肯定先选小的费用,再走大的费用
#include<bits/stdc++.h> using namespace std; const int N = 610, inf = 0x3f3f3f3f; struct edge { int nxt, to, f; long long c; } e[N * N << 2]; int n, m, k, source, sink, tot, cnt = 1, sum; int a[N][N], head[N], pree[N], prev[N], t[N], vis[N], w[N], day[N], c[N], l[N], p[N]; long long d[N]; inline void link(int u, int v, int f, long long c) { e[++cnt].nxt = head[u]; head[u] = cnt; e[cnt].f = f; e[cnt].to = v; e[cnt].c = c; } inline void insert(int u, int v, int f, int c) { link(u, v, f, c); link(v, u, 0, -c); } bool spfa() { memset(d, -1, sizeof(d)); d[source] = 0; queue<int> q; q.push(source); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(int i = head[u]; i; i = e[i].nxt) if(e[i].f && (d[e[i].to] > d[u] + e[i].c || d[e[i].to] == -1)) { pree[e[i].to] = i; prev[e[i].to] = u; d[e[i].to] = d[u] + e[i].c; if(vis[e[i].to] == 0) { q.push(e[i].to); vis[e[i].to] = 1; } } } return d[sink] != -1; } inline long long Edmonds_Karp() { long long ans = 0; while(spfa()) { int now = sink, delta = inf; while(now != source) { delta = min(delta, e[pree[now]].f); now = prev[now]; } now = sink; while(now != source) { e[pree[now]].f -= delta; e[pree[now] ^ 1].f += delta; now = prev[now]; } ans += (long long)delta * d[sink]; } return ans; } int main() { cin >> m >> n; source = 0; sink = m + n + 1; for(int i = 1; i <= n; ++i) { int c; scanf("%d", &c); insert(i + m, sink, c, 0); } for(int i = 1; i <= m; ++i) for(int j = 1; j <= n; ++j) { int x; scanf("%d", &x); if(x == 1) insert(i, j + m, inf, 0); } for(int i = 1; i <= m; ++i) { int s; scanf("%d", &s); for(int j = 1; j <= s; ++j) scanf("%d", &t[j]); t[++s] = inf; for(int j = 1; j <= s; ++j) { long long w; scanf("%lld", &w); insert(source, i, t[j] - t[j - 1], w); } } cout << Edmonds_Karp(); return 0; }