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