[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=2879
[算法]
首先 , 将每种食物建一个点 , 将每位厨师做的每一道菜建一个点
建图如下 :
1. 将原点与每种食物连一条流量为Ai , 费用为0的边
2. 将每种食物像每位厨师的每道菜连一条流量为1 , 费用为Ti,j * k的边(其中 , i表示第i种食物 , j表示第j位厨师 , k表示该厨师做的倒数第k道菜)
3. 将每位厨师做的每道菜向汇点连一条流量为1 , 费用为0的边
在这张图上跑最小费用最大流即为答案
由于边太多 , 我们需要动态加边 , 否则将无法在时限内通过此题
时间复杂度 : O(Costflow(NM + P , NMP))
[代码]
#include<bits/stdc++.h> using namespace std; #define MAXN 80 #define MAXM 110 #define MAXP 1010 const int INF = 2e9; struct edge { int to , w , cost , nxt; } e[MAXN * MAXM * MAXP]; int n , m , cnt , tot , ans , S , T; int a[MAXN] , dist[MAXM * MAXP] , head[MAXM * MAXP] , pre[MAXM * MAXP] , incf[MAXM * MAXP]; int t[MAXN][MAXM]; bool inq[MAXM * MAXP]; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline void addedge(int u , int v , int w , int cost) { ++tot; e[tot] = (edge){v , w , cost , head[u]}; head[u] = tot; ++tot; e[tot] = (edge){u , 0 , -cost , head[v]}; head[v] = tot; } inline bool spfa() { queue< int > q; for (int i = 1; i <= T; i++) { dist[i] = INF; incf[i] = INF; inq[i] = false; pre[i] = 0; } q.push(S); inq[S] = true; dist[S] = 0; while (!q.empty()) { int cur = q.front(); q.pop(); inq[cur] = false; for (int i = head[cur]; i; i = e[i].nxt) { int v = e[i].to , w = e[i].w , cost = e[i].cost; if (w > 0 && dist[cur] + cost < dist[v]) { dist[v] = dist[cur] + cost; pre[v] = i; incf[v] = min(incf[cur] , w); if (!inq[v]) { q.push(v); inq[v] = true; } } } } if (dist[T] < INF) return true; else return false; } inline void update() { int now = T; while (now != S) { int pos = pre[now]; e[pos].w -= incf[T]; e[pos ^ 1].w += incf[T]; now = e[pos ^ 1].to; } ans += dist[T] * incf[T]; int pos = (e[pre[T] ^ 1].to - n - 1) / cnt + 1 , v = (e[pre[T] ^ 1].to - n - 1) % cnt + 1; for (int i = 1; i <= n; i++) addedge(i , e[pre[T] ^ 1].to + 1 , 1 , t[i][pos] * (v + 1)); } int main() { read(n); read(m); for (int i = 1; i <= n; i++) { read(a[i]); cnt += a[i]; } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { read(t[i][j]); } } tot = 1; S = n + m * cnt + 1 , T = S + 1; for (int i = 1; i <= n; i++) addedge(S , i , a[i] , 0); for (int i = 1; i <= m * cnt; i++) addedge(n + i , T , 1 , 0); for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { addedge(i , n + (j - 1) * cnt + 1 , 1 , t[i][j]); } } while (spfa()) update(); printf("%d " , ans); return 0; }