题目大意
现在有
N
种人,每种人有
N≤40
M≤100
∑Pi≤800
解题思路
设
Sum=∑Pi
。
我们考虑用网络流做这题,我们把第
i
个厨师差拆成
但是这样肯定会超时!因为边太多了。所以我们可以考虑动态加边,对于每个厨师,做完代表倒数
程序
//YxuanwKeith
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 100000;
int All, S, T, N, M, Min, P[50], t[50][1000], D[MAXN];
int tot, Last[MAXN], Go[MAXN * 2], Len[MAXN * 2], Next[MAXN * 2], Cost[MAXN * 2], Dis[MAXN];
bool Flag[MAXN], Bz[MAXN];
void Open(int u, int v, int flow, int cost) {
Next[++ tot] = Last[u], Last[u] = tot, Go[tot] = v, Len[tot] = flow, Cost[tot] = cost;
}
void Link(int u, int v, int flow, int cost) {
Open(u, v, flow, cost);
Open(v, u, 0, -cost);
}
void Add(int Num, int Cnt) {
int Ord = (Num - 1) * All + Cnt;
if (Cnt > All || Flag[Ord]) return;
Flag[Ord] = 1;
Link(S, Ord, 1, 0);
for (int i = 1; i <= N; i ++) Link(Ord, All * M + i, 1, t[i][Num] * Cnt);
}
int Dfs(int Now, int flow) {
if (Now == T) {
Min += Dis[T] * flow;
return flow;
}
int Use = 0;
Bz[Now] = 1;
for (int p = Last[Now]; p; p = Next[p]) {
int v = Go[p];
if (Dis[v] == Dis[Now] + Cost[p] && Len[p] > 0 && !Bz[v]) {
int t = Dfs(v, min(flow - Use, Len[p]));
Len[p] -= t, Len[p ^ 1] += t, Use += t;
if (Use == flow) {
if (Now <= All * M && Now != S) Add((Now - 1) / All + 1,(Now - 1) % All + 2);
return Use;
}
}
}
return Use;
}
void Go_Flow() {
int Cnt = 0;
while (1 == 1) {
memset(Bz, 0, sizeof Bz), memset(Dis, 60, sizeof Dis);
int Inf = Dis[0];
int l = 0, r = 1;
D[1] = S, Dis[S] = 0;
while (l != r) {
l = (l + 1) % MAXN;
int Now = D[l];
for (int p = Last[Now]; p; p = Next[p]) {
int v = Go[p];
if (Len[p] && Dis[v] > Dis[Now] + Cost[p]) {
Dis[v] = Dis[Now] + Cost[p];
if (!Bz[v]) {
Bz[v] = 1;
r = (r + 1) % MAXN;
D[r] = v;
}
}
}
Bz[Now] = 0;
}
if (Dis[T] == Inf) return;
Dfs(S, Inf);
}
}
int main() {
scanf("%d%d", &N, &M);
for (int i = 1; i <= N; i ++) {
scanf("%d", &P[i]);
All += P[i];
}
S = 0, T = All * M + N + 1;
tot = 1;
for (int i = 1; i <= N; i ++) {
Link(All * M + i, T, P[i], 0);
for (int j = 1; j <= M; j ++) scanf("%d", &t[i][j]);
}
for (int i = 1; i <= M; i ++) Add(i, 1);
Go_Flow();
printf("%d\n", Min);
}