题解:学习了动态加边,可以说是进一步理解了网络流。具体思路就是考虑每一道菜,如果这是该位厨师最后一次做,那么等待时间就是做这道菜的时间,如果是倒数第二次做,就要两倍时间(目前做了一次,后面还有等待的一次时间)……,对于其他菜以此类推。那么可以这样考虑,当这位厨师倒一次做的边没有流量的时候,是不可能用到倒二次做的边(因为费用流会优先选择费用小的边,而我们的时间花费即为费用,故倒一次没用不可能使用倒二次),于是乎可以在跑完每次最短路的时候,判断这次是从哪个厨师的哪个点转移来的,紧接着连上接下来的一个点(倒一就连倒二,倒二就倒三……)。
#pragma comment(linker, "/STACK: 1024000000,1024000000")#include#define pb push_back#define mp make_pair#define eb emplace_back#define em emplace#define pii pair #define de(x) cout << #x << " = " << x << endl#define clr(a,b) memset(a,b,sizeof(a))#define INF (0x3f3f3f3f)#define LINF ((long long)(0x3f3f3f3f3f3f3f3f))#define F first#define S secondusing namespace std;inline int getint(){ int _x=0; char _tc=getchar(); while(_tc<'0'||_tc>'9') _tc=getchar(); while(_tc>='0'&&_tc<='9') _x*=10,_x+=(_tc-'0'),_tc=getchar(); return _x;}const int M = 1e5 + 15;const int N = 110;int T[N][N];int p[N], P;int n, m, st, ed;struct Edge{ int u, v, c, w, nxt; Edge(){} Edge( int t2, int t3, int t4, int t5, int t6 ) : u(t2), v(t3), c(t4), w(t5), nxt(t6) {}};Edge e[M<<4];int ect;int pr[M], h[M], d[M];bool vis[M];int ans = 0;void _add( int u, int v, int c, int w ){ e[ect].u = u; e[ect].v = v; e[ect].c = c; e[ect].w = w; e[ect].nxt = h[u]; h[u] = ect ++; e[ect].u = v; e[ect].v = u; e[ect].c = 0; e[ect].w = -w; e[ect].nxt = h[v]; h[v] = ect ++;}void init(){ clr(h,-1); P = ect = 0;}bool spfa(){ clr(d,INF); clr(vis,false); clr(pr,-1); queue Q; Q.push( st ); d[st] = 0; vis[st] = true; while ( !Q.empty() ) { int u = Q.front(); Q.pop(); vis[u] = false; for ( int i = h[u]; i + 1; i = e[i].nxt ) { int v = e[i].v; if ( e[i].c > 0 && d[v] > d[u] + e[i].w ) { d[v] = d[u] + e[i].w; pr[v] = i; if ( !vis[v] ) { vis[v] = true; Q.push(v); } } } } return d[ed] != INF;}void mcf(){ int f = INF; for ( int i = ed; i != st; i = e[pr[i]].u ) f = min( f, e[pr[i]].c ); for ( int i = ed; i != st; i = e[pr[i]].u ) { e[pr[i]].c -= f, e[pr[i]^1].c += f; ans += f*e[pr[i]].w; } int x = e[pr[ed]].u; int nw = (x-n-1)/P + 1, th = (x-n)%P + 1; if ( th <= P ) { for ( int i = 1; i <= n; i ++ ) _add( i, n+(nw-1)*P+th, 1, th*T[i][nw] ); } _add( n+(nw-1)*P+th, ed, 1, 0 );}int main(){ init(); scanf("%d%d", &n, &m); for ( int i = 1; i <= n; i ++ ) scanf("%d", &p[i]), P += p[i]; for ( int i = 1; i <= n; i ++ ) for ( int j = 1; j <= m; j ++ ) scanf("%d", &T[i][j]); st = 0, ed = n + 1 + P*m; for ( int i = 1; i <= n; i ++ ) { _add( st, i, p[i], 0 ); for ( int j = 1; j <= m; j ++ ) _add( i, n+(j-1)*P+1, 1, T[i][j] ); } for ( int i = 1; i <= m; i ++ ) _add( n+(i-1)*P+1, ed, 1, 0 ); while ( spfa() ) mcf(); printf("%d\n", ans); return 0;}