P2488 [SDOI2011]工作安排 费用流

(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;
}
原文地址:https://www.cnblogs.com/olinr/p/10357255.html