描述 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
源点与产品连边容量 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;
}