【模板】最小费用最大流(动态开节点(待解决))

修车车喽~

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;
}

 

posted @ 2020-11-07 22:09  Wans_ovo  阅读(142)  评论(0编辑  收藏  举报