【模板】最小费用最大流(动态开节点(待解决))
修车车喽~
P2053 [SCOI2007]修车
注意建图的时候不仅要关注第$i$辆车给第$j$个人修,还要排是第几个修,所以干脆直接拆成$n*m$个点代表$i,j$,连向$k$次序点。边费用应该是后面$(n-k)辆的等待时间+这辆修的时间=(n-k+1)*a(当前这辆所需时间)$
又背了一个板子叻!打卡完成今日任务!
贴上以前的丑丑代码,略微修改。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define oo 2147483647 using namespace std; #define ll long long int m, n; const int N = 100005; const int M = 2000005; int s, t; ll stot = 1, tov[M], f[M], nex[M], h[N], w[M]; void add ( int u, int v, int ff, int ww ) { tov[++stot] = v; f[stot] = ff; w[stot] = ww; nex[stot] = h[u]; h[u] = stot; tov[++stot] = u; f[stot] = 0; w[stot] = -ww; nex[stot] = h[v]; h[v] = stot; } ll mincost; double maxflow; ll vis[N], dis[N], preu[N], prei[N]; queue < int > q; bool spfa ( ) { memset ( vis, 0, sizeof ( vis ) ); memset ( dis, 127, sizeof ( dis ) ); vis[s] = 1; q.push( s ); dis[s] = 0; while ( !q.empty( ) ) { int u = q.front ( ); vis[u] = 0; q.pop ( ); for ( int i = h[u]; i; i = nex[i] ) { int v = tov[i]; if ( dis[v] > dis[u] + w[i] && f[i] ) { dis[v] = dis[u] + w[i]; preu[v] = u; prei[v] = i; if ( !vis[v] ) { vis[v] = 1; q.push ( v ); } } } } return dis[t] < oo; } void doge ( ) { ll u = t, delta = oo; while ( u != s ) { delta = min ( delta, f[prei[u]] ); u = preu[u]; } u = t; while ( u != s ) { int i = prei[u]; f[i] -= delta; f[i^1] += delta; u = preu[u]; } mincost += delta * dis[t]; maxflow += delta; } int main ( ) { scanf ( "%d%d", &m, &n ); s = 0, t = n*m+n+1; for ( int i = 1; i <= n; i ++ ) { for ( int j = 1; j <= m; j ++ ) { int a; scanf ( "%d", &a ); for ( int k = 1; k <= n; k ++ ) add ( n*(j-1)+k, i+n*m, 1, (n-k+1) *a ); } } for ( int i = 1; i <= m*n; i ++ ) add ( s, i, 1, 0 ); for ( int i = n*m+1; i <= n*m+n; i ++ ) add ( i, t, 1, 0 ); while ( spfa ( ) ) doge ( ); printf ( "%.2lf", 1.0*mincost/n ); return 0; }