题目大意:好长,如果不想看可以先看看修车那个题,基本一样。
思路:做过修车就好办了。这个题仅仅是数据范围变大了一坨。建图就不说了,主要是动态加边。倒过来做,因为一个厨师最后一个菜做的时间是不会影响到其他菜的时间的。而且每一个厨师确定了最后一个菜才能去想倒数第二个菜是什么。所以每跑一次SPFA,就回来看看是哪个厨师做的菜,然后在多加一个点限制一下流量,将这个点连向所有的菜。
CODE:
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 110 #define MAXP 100010 #define MAXE 200010 #define INF 0x3f3f3f3f #define S 0 #define T (MAXP - 1) using namespace std; int cooks,chefs; int need[MAX]; int src[MAX][MAX],cnt; int now[MAX]; struct MinCostMaxFlow{ int head[MAXP],total; int _next[MAXE],aim[MAXE],flow[MAXE],cost[MAXE]; int f[MAXP],from[MAXP],p[MAXP]; bool v[MAXP]; MinCostMaxFlow() { total = 1; } void Add(int x,int y,int f,int c) { _next[++total] = head[x]; aim[total] = y; flow[total] = f; cost[total] = c; head[x] = total; } void Insert(int x,int y,int f,int c) { Add(x,y,f,c); Add(y,x,0,-c); } void Initialize() { for(int i = 1; i <= chefs; ++i) { Insert(i,++cnt,1,0); for(int j = 1; j <= cooks; ++j) Insert(cnt,chefs + j,1,src[j][i]); } } bool SPFA() { static queue<int> q; while(!q.empty()) q.pop(); memset(f,0x3f,sizeof(f)); f[S] = 0; q.push(S); while(!q.empty()) { int x = q.front(); q.pop(); v[x] = false; for(int i = head[x]; i; i = _next[i]) if(flow[i] && f[aim[i]] > f[x] + cost[i]) { f[aim[i]] = f[x] + cost[i]; if(!v[aim[i]]) { v[aim[i]] = true; q.push(aim[i]); } from[aim[i]] = x; p[aim[i]] = i; } } return f[T] != INF; } int EdmondsKarp() { int re = 0; while(SPFA()) { int remain_flow = INF; for(int i = T; i != S; i = from[i]) remain_flow = min(remain_flow,flow[p[i]]); static int k,temp; for(int i = T; i != S; i = from[i]) { flow[p[i]] -= remain_flow; flow[p[i]^1] += remain_flow; if(i <= chefs && i >= 1) k = i; if(i != T && i > chefs) temp = i; } ++now[k]; Insert(k,++cnt,1,0); for(int i = 1; i <= cooks; ++i) Insert(cnt,chefs + i,1,(now[k] + 1) * src[i][k]); re += f[T] * remain_flow; } return re; } }solver; int main() { cin >> cooks >> chefs; for(int i = 1; i <= cooks; ++i) scanf("%d",&need[i]); for(int i = 1; i <= cooks; ++i) for(int j = 1; j <= chefs; ++j) scanf("%d",&src[i][j]); for(int i = 1; i <= chefs; ++i) solver.Insert(S,++cnt,INF,0); int p = 0; for(int i = 1; i <= cooks; ++i) { solver.Insert(++cnt,T,need[i],0); p += need[i]; } solver.Initialize(); cout << solver.EdmondsKarp() << endl; return 0; }