P4177 [CEOI2008]order

如果没有租用机器这一操作,做法同 P2762 太空飞行计划问题,用最大权闭合子图模型解决。

考虑如何在经典方法构造的新图中体现租用机器这一操作。

新图中对于工作和它所需的机器之间的容量为 \(+\infty\) , 意义即为选择这个工作就必须购买这个机器。

那么 ‘租用’ 就可以将这条边的容量改为 \(b_{ij}\) , 表示选择这个工作后,可以花费 \(b_{i,j}\) 的代价代替购买机器。

其它的仍同最大权闭合子图模型。

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define Inf 0x3f3f3f3f

const int MAXN = 2400 , MAXM = MAXN * ( MAXN + 1 );
struct Edge {
    int v , flw , nxt;
    Edge(){}
    Edge( int V , int Flw , int Nxt ) { v = V , flw = Flw , nxt = Nxt; }
}Graph[ 2 * MAXM + 5 ];
int Head[ MAXN + 5 ] , Enum = 1;
void Add_Edge( int u , int v , int flw ) {
    Graph[ ++ Enum ] = Edge( v , flw , Head[ u ] ); Head[ u ] = Enum;
    Graph[ ++ Enum ] = Edge( u , 0   , Head[ v ] ); Head[ v ] = Enum;
}
int cur[ MAXN + 5 ] , lev[ MAXN + 5 ];
bool Layer( int S , int T ) {
    memcpy( cur , Head , sizeof( Head ) );
    memset( lev , -1 , sizeof( lev ) );
    queue< int > Que;
    lev[ S ] = 0 , Que.push( S );
    while( !Que.empty() ) {
        int u = Que.front(); Que.pop();
        for( int i = Head[ u ] ; i ; i = Graph[ i ].nxt ) {
            int v = Graph[ i ].v , flw = Graph[ i ].flw;
            if( flw && lev[ v ] == -1 )
                lev[ v ] = lev[ u ] + 1 , Que.push( v );
        }
    }
    return lev[ T ] != -1;
}
int dfs( int u , int t , int f ) {
    if( u == t ) return f;
    for( int &i = cur[ u ] ; i ; i = Graph[ i ].nxt ) {
        int v = Graph[ i ].v , flw = Graph[ i ].flw;
        if( flw && lev[ v ] == lev[ u ] + 1 ) {
            int d = dfs( v , t , min( f , flw ) );
            if( d ) {
                Graph[ i ].flw -= d , Graph[ i ^ 1 ].flw += d;
                return d;
            }
        }
    }
    return 0;
}
int Dinic( int S , int T ) {
    int Mxf = 0;
    while( Layer( S , T ) ) for( int fl = 0 ; ( fl = dfs( S , T , Inf ) ) > 0 ; Mxf += fl );
    return Mxf;
}

int n , m , s , t , val[ MAXN + 5 ];

int main( ) {
    scanf("%d %d",&m,&n); s = n + m + 1,  t = s + 1;
    for( int i = 1 , p ; i <= m ; i ++ ) {
        scanf("%d %d",&val[ n + i ],&p);
        for( int j = 1 , id , ct ; j <= p ;j ++ ) {
            scanf("%d %d",&id,&ct);
            Add_Edge( n + i , id , ct );
        }
    }
    for( int i = 1 ; i <= n ; i ++ ) scanf("%d",&val[ i ]) , val[ i ] *= -1;

    int all = 0;
    for( int i = 1 ; i <= n + m ; i ++ ) {
        if( val[ i ] > 0 ) Add_Edge( s , i , val[ i ] ) , all += val[ i ];
        if( val[ i ] < 0 ) Add_Edge( i , t , -val[ i ] );
    }
    printf("%d\n", all - Dinic( s , t ) );
    return 0;
}
posted @ 2021-04-08 21:13  chihik  阅读(26)  评论(0编辑  收藏  举报