P2488 [SDOI2011]工作安排 費用流
阿新 • • 發佈:2019-02-09
CMF min png from 使用 輸入格式 描述 != 輸入 \(\color{#0066ff}{數據範圍與提示}\)
\(\color{#0066ff}{ 題目描述 }\)
你的任務是制定出一個產品的分配方案,使得訂單條件被滿足,並且所有員工的憤怒值之和最小。由於我們並不想使用Special Judge,也為了使選手有更多的時間研究其他兩道題目,你只需要輸出最小的憤怒值之和就可以了。
\(\color{#0066ff}{輸入格式}\)
\(\color{#0066ff}{輸出格式}\)
僅輸出一個整數,表示最小的憤怒值之和。
\(\color{#0066ff}{輸入樣例}\)
2 3
2 2 2
1 1 0
0 0 1
1
2
1 10
1
2
1 6
\(\color{#0066ff}{輸出樣例}\)
24
\(\color{#0066ff}{數據範圍與提示}\)
\(\color{#0066ff}{ 題解 }\)
顯然是個費用流
考慮怎麽建邊
憤怒值對於每個員工完成工作的數量來分段
完成工作數量? 這不就是從員工流出去多少流嗎
所以,從S向員工,連多條邊,每條邊的容量為每段的長
這樣憤怒值的問題就解決了
註意,每個任務不止完成一次
所以員工向任務連容量為inf的邊,任務向T連容量為需要次數的邊
#include<bits/stdc++.h> #define LL long long LL in() { char ch; LL x = 0, f = 1; while(!isdigit(ch = getchar()))(ch == '-') && (f = -f); for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48)); return x * f; } const int maxn = 1e5; const LL inf = 999999999999999LL; struct node { int to; LL dis, can; node *nxt, *rev; node(int to = 0, LL dis = 0, LL can = 0, node *nxt = NULL) : to(to), dis(dis), can(can), nxt(nxt) {} void *operator new (size_t) { static node *S = NULL, *T = NULL; return (S == T) && (T = (S = new node[1024]) + 1024), S++; } }; LL dis[maxn], change[maxn]; node *head[maxn], *road[maxn]; bool vis[maxn]; bool f[505][505]; int n, s, t, m; std::vector<LL> v[maxn], d[maxn]; bool spfa() { for(int i = s; i <= t; i++) dis[i] = inf, change[i] = inf; std::queue<int> q; dis[s] = 0; q.push(s); while(!q.empty()) { int tp = q.front(); q.pop(); vis[tp] = false; for(node *i = head[tp]; i; i = i->nxt) if(dis[i->to] > dis[tp] + i->dis && i->can) { dis[i->to] = dis[tp] + i->dis; change[i->to] = std::min(change[tp], i->can); road[i->to] = i; if(!vis[i->to]) vis[i->to] = true, q.push(i->to); } } return change[t] != inf; } LL mcmf() { LL cost = 0; while(spfa()) { cost += change[t] * dis[t]; for(int o = t; o != s; o = road[o]->rev->to) { road[o]->can -= change[t]; road[o]->rev->can += change[t]; } } return cost; } void add(int from, int to, LL dis, LL can) { head[from] = new node(to, dis, can, head[from]); } void link(int from, int to, LL dis, LL can) { add(from, to, dis, can); add(to, from, -dis, 0); head[from]->rev = head[to]; head[to]->rev = head[from]; } int main() { m = in(), n = in(); t = m + n + 1, s = 0; for(int i = m + 1; i <= m + n; i++) link(i, t, 0, in()); for(int i = 1; i <= m; i++) for(int j = 1; j <= n; j++) if(in()) link(i, m + j, 0, inf); for(int i = 1; i <= m; i++) { int k = in(); v[i].push_back(0); for(int j = 1; j <= k; j++) v[i].push_back(in()); v[i].push_back(inf); for(int j = 1; j <= k + 1; j++) d[i].push_back(in()); for(int j = 0; j <= k; j++) link(s, i, d[i][j], v[i][j + 1] - v[i][j]); } printf("%lld", mcmf()); return 0; }
P2488 [SDOI2011]工作安排 費用流