BZOJ 1449: [JSOI2009]球队收益( 最小费用最大流)
先考虑假如全部输了的收益. 再考虑每场比赛球队赢了所得收益的增加量,用这个来建图..
--------------------------------------------------------------------------------------------------
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
#define rep( i , n ) for( int i = 0 ; i < n ; ++i )
#define clr( x , c ) memset( x , c , sizeof( x ) )
#define Rep( i , n ) for( int i = 1 ; i <= n ; ++i )
using namespace std;
const int maxn = 6000 + 5;
const int INF = 0x3f3f3f3f;
struct edge {
int to , cap , cost;
edge *next , *rev;
};
edge* pt;
edge* head[ maxn ];
edge EDGE[ 20000 ];
void init() {
pt = EDGE;
clr( head , 0 );
}
inline void add( int u , int v , int d , int w ) {
pt -> to = v;
pt -> cap = d;
pt -> cost = w;
pt ->next = head[ u ];
head[ u ] = pt++;
}
inline void add_edge( int u , int v , int d , int w ) {
add( u , v , d , w );
add( v , u , 0 , -w );
head[ u ] -> rev = head[ v ];
head[ v ] -> rev = head[ u ];
}
edge* p[ maxn ];
int d[ maxn ] , a[ maxn ] , inQ[ maxn ];
int min_cost( int S , int T ) {
int cost = 0;
for( ; ; ) {
clr( d , INF );
d[ S ] = 0;
clr( inQ , 0 );
queue< int > Q;
a[ S ] = INF , Q.push( S );
while( ! Q.empty() ) {
int x = Q.front();
Q.pop();
inQ[ x ] = false;
for( edge* e = head[ x ] ; e ; e = e -> next )
if( e -> cap > 0 && d[ e -> to ] > d[ x ] + e -> cost ) {
int to = e -> to;
d[ to ] = d[ x ] + e -> cost;
a[ to ] = min( a[ x ] , e -> cap );
p[ to ] = e;
if( ! inQ[ to ] )
Q.push( to ) , inQ[ to ] = true;
}
}
if( d [ T ] == INF ) break;
cost += d[ T ] * a[ T ];
int x = T;
while( x != S ) {
p[ x ] -> cap -= a[ T ];
p[ x ] -> rev -> cap += a[ T ];
x = p[ x ] -> rev -> to;
}
}
return cost;
}
int win[ maxn ] , lose[ maxn ];
int C[ maxn ] , D[ maxn ];
int cnt[ maxn ];
int main() {
init();
int n , m;
cin >> n >> m;
int s = 0 , t = n + m + 1;
Rep( i , n ) {
scanf( "%d%d%d%d" , &win[ i ] , &lose[ i ] , &C[ i ] , &D[ i ] );
cnt[ i ] = 0;
}
Rep( i , m ) {
int u , v;
scanf( "%d%d" , &u , &v );
cnt[ u ]++ , cnt[ v ]++;
add_edge( s , i , 1 , 0 );
add_edge( i , u + m , 1 , 0 );
add_edge( i , v + m , 1 , 0 );
}
int ans = 0;
Rep( i , n ) {
int x = i + m;
lose[ i ] += cnt[ i ];
ans += C[ i ] * win[ i ] * win[ i ] + D[ i ] * lose[ i ] * lose[ i ];
while( cnt[ i ]-- ) {
add_edge( x , t , 1 , 2 * ( C[ i ] * win[ i ] - D[ i ] * lose[ i ] ) + C[ i ] + D[ i ] );
win[ i ]++;
lose[ i ]--;
}
}
cout << min_cost( s , t ) + ans << "\n";
return 0;
}
--------------------------------------------------------------------------------------------------
1449: [JSOI2009]球队收益
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 500 Solved: 272
[Submit][Status][Discuss]
Description
![](http://www.lydsy.com/JudgeOnline/images/1449_1.jpg)
Input
![](http://www.lydsy.com/JudgeOnline/images/1449_2.jpg)
Output
一个整数表示联盟里所有球队收益之和的最小值。
Sample Input
3 3
1 0 2 1
1 1 10 1
0 1 3 3
1 2
2 3
3 1
1 0 2 1
1 1 10 1
0 1 3 3
1 2
2 3
3 1
Sample Output
43
HINT
Source