NOI2012 美食节 动态加边维护费用流
2016-08-19 22:20
363 查看
题目大意
现在有N种人,每种人有Pi个,还有M个厨师,第j个厨师给第i种人做菜需要时间Ti,j,并且同一时间一个厨师只能做一道菜。每个人的权值是这个人等待的时间。问所有人的权值和最小是多少。N≤40
M≤100
∑Pi≤800
解题思路
设Sum=∑Pi。我们考虑用网络流做这题,我们把第i个厨师差拆成Sum个点,第k个点表示这个厨师做的倒数第k道菜,每个点向每个人j连一条流量为1,费用为Tj,i∗k,向T连一条流量为1,费用为0的边。每个人想S连一条流量为Pi,费用为0的边。显然跑一次最小费用最大流的费用就是答案。
但是这样肯定会超时!因为边太多了。所以我们可以考虑动态加边,对于每个厨师,做完代表倒数k个菜的点才把代表倒数k+1个菜的点加进去即动态加边,就能大大减少网络流遍历边的时间,并且我们不用但新是否会流了代表倒数第k个菜的点,但是没流代表倒数第k−1个菜的点,因为我们肯定会优先流费用小的边。
程序
//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); }
相关文章推荐
- bzoj 2879: [Noi2012]美食节(费用流+动态加边)
- bzoj2879 [Noi2012]美食节 [费用流动态加边]
- 2879: [Noi2012]美食节 动态加边 费用流
- 【费用流+动态加边】[NOI2012]美食节
- [NOI2012][bzoj2879] 美食节 [费用流+动态加边]
- bzoj 2879: [Noi2012]美食节 费用流+动态加边
- [BZOJ2879][Noi2012]美食节 && 动态加边费用流
- [NOI2012]美食节(费用流+动态开点)
- BZOJ 2879: [Noi2012]美食节( 费用流 + 动态加边 )
- BZOJ 2879: [Noi2012]美食节 费用流 动态加边
- BZOJ 2879 [Noi2012]美食节 | 费用流 动态开点
- bzoj2879 [Noi2012]美食节(动态加边费用流)
- BZOJ 2879 NOI2012 美食节 费用流
- bzoj2879 [NOI2012]美食节(费用流)
- 【BZOJ2879】[Noi2012]美食节 动态加边网络流
- 2879: [Noi2012]美食节 (最小费用最大流+动态加边)
- BZOJ2879 [Noi2012]美食节 【费用流】
- BZOJ 2879 NOI 2012 美食节 费用流
- BZOJ2879 [Noi2012]美食节 【费用流】
- bzoj 2879 [Noi2012]美食节 费用流