[BZOJ2245]&&[SDOI2011] 工作安排

描述 Description

你的公司接到了一批订单。订单要求你的公司提供 n 类产品,产品被编号为 1~n,其中第 i 类产品共需要 Ci 件。公司共有 m 名员工,员工被编号为 1~m 员工能够制造的产品种类有所区别。一件产品必须完整地由一名员工制造,不可以由某名员工制造一部分配件后,再转交给另外一名员工继续进行制造。

我们用一个由 0 和 1 组成的 m*n 的矩阵 A 来描述每名员工能够制造哪些产品。矩阵的行和列分别被编号为 1~m 和 1~n,Ai,j 为 1 表示员工 i 能够制造产品 j,为 0 表示员工 i 不能制造产品 j。

如果公司分配了过多工作给一名员工,这名员工会变得不高兴。我们用愤怒值来描述某名员工的心情状态。愤怒值越高,表示这名员工心情越不爽,愤怒值越低,表示这名员工心情越愉快。员工的愤怒值与他被安排制造的产品数量存在某函数关系,鉴于员工们的承受能力不同,不同员工之间的函数关系也是有所区别的。

对于员工 i,他的愤怒值与产品数量之间的函数是一个 Si+1 段的分段函数。当他制造第 1~Ti,1 件产品时,每件产品会使他的愤怒值增加 Wi,1,当他制造第 Ti,1+1~Ti,2 件产品时,每件产品会使他的愤怒值增加 Wi,2…… 为描述方便,设 Ti,0=0,Ti,si+1=+∞,那么当他制造第 Ti,j-1+1~Ti,j 件产品时,每件产品会使他的愤怒值增加 Wi,j, 1≤j≤Si+1。

你的任务是制定出一个产品的分配方案,使得订单条件被满足,并且所有员工的愤怒值之和最小。由于我们并不想使用 Special Judge,也为了使选手有更多的时间研究其他两道题目,你只需要输出最小的愤怒值之和就可以了。

输入格式 InputFormat

第一行包含两个正整数 m 和 n,分别表示员工数量和产品的种类数;

第二行包含 n 个正整数,第 i 个正整数为 Ci;

以下 m 行每行 n 个整数描述矩阵 A;

下面 m 个部分,第 i 部分描述员工 i 的愤怒值与产品数量的函数关系。每一部分由三行组成:第一行为一个非负整数 Si,第二行包含 Si 个正整数,其中第 j 个正整数为 Ti,j,如果 Si=0 那么输入将不会留空行(即这一部分只由两行组成)。第三行包含 Si+1 个正整数,其中第 j 个正整数为 Wi,j。

输出格式 OutputFormat

仅输出一个整数,表示最小的愤怒值之和。

样例输入 SampleInput

2 3
2 2 2
1 1 0
0 0 1
1
2
1 10
1
2
1 6

样例输出 SampleOutput

24


BZOJ 2245


源点与产品连边容量 Ci 费用 0,员工按照分段函数拆点与可制造的产品连边容量无限费用零,并与汇点连边容量 T[i]-T[i-1] 费用 W[i],mcmf.

long long 的速度不忍直视。。。

换了一个编辑器感觉自己代码风格一下提高了←_←

#include <stdio.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
#define ll long long
const int inf = 0x7fffffff / 27.11;
const int maxn = 505;
const int maxm = maxn * maxn;
int i, j, t, n, m, l, r, k, z, y, x;
struct edge
{
    int to, fl, co, nx;
} e[maxm];
int head[maxn], dis[maxn], used[maxn], pre[maxn];
int c[maxn], a[maxn];
int cnt, num, s;
deque <int> q;
inline void ins(int u, int v, int f, int c)
{
    e[cnt] = (edge)
    {
        v, f, c, head[u]
    };
    head[u] = cnt++;
    e[cnt] = (edge)
    {
        u, 0, -c, head[v]
    };
    head[v] = cnt++;
}
inline bool spfa(int s, int t, int tim)
{
    int i, u, v, w;
    while (!q.empty()) q.pop_front();
    for (i = s; i <= t; i++) dis[i] = inf;
    dis[s] = 0; used[s] = tim; pre[s] = -1;
    q.push_back(s);
    while (!q.empty())
    {
        u = q.front(); q.pop_front(); used[u] = 0;
        for (i = head[u]; i != -1; i = e[i].nx)
        {
            v = e[i].to; w = e[i].co;
            if (dis[v] > dis[u] + w && e[i].fl > 0)
            {
                dis[v] = dis[u] + w;
                pre[v] = i;
                if (used[v] != tim)
                {
                    used[v] = tim;
                    if (!q.empty() && dis[v] < dis[q.front()]) q.push_front(v);
                    else q.push_back(v);
                }
            }
        }
    }
    return (dis[t] != inf);
}
inline void mcmf(int s, int t)
{
    int i, f;
    ll ans = 0;
    while (spfa(s, t, ++num))
    {
        for (f = inf, i = pre[t]; i != -1; i = pre[e[i ^ 1].to]) f = min(f, e[i].fl);
        for (i = pre[t]; i != -1; i = pre[e[i ^ 1].to]) e[i].fl -= f, e[i ^ 1].fl += f;
        ans += f * dis[t];
    }
    printf("%lld\n", ans);
}
int main()
{
    cnt = num = 0;
    memset(head, -1, sizeof(head));
    scanf("%d%d", &m, &n);
    for (i = 1; i <= n; i++) scanf("%d", &x), ins(0, i, x, 0);
    for (i = 1; i <= m; i++)
        for (j = 1; j <= n; j++)
        {
            scanf("%d", &x);
            if (x == 1) ins(j, n + i, inf, 0);
        }
    for (i = 1; i <= m; i++)
    {
        scanf("%d", &s);
        for (j = 1; j <= s; j++) scanf("%d", &a[j]); a[s + 1] = inf;
        for (j = 1; j <= s + 1; j++) scanf("%d", &x), ins(n + i, n + m + 1, a[j] - a[j - 1], x);
    }
    mcmf(0, m + n + 1);
    return 0;
}