Description
经典的最小费用最大流问题是这样的。我们需要把一些石油从产油地s运往耗油地t,途中有若干根有向的管道,每根管道有一个容量上限cap,即最多有cap单位的油这根管道经过;每根管道还有一个费用cost,每单位油从这根管道经过需要花费cost的钱。你需要求出在输油量最大的前提下,最少花费多少钱。
现在我们的有向图如下图。
每个点没有容量限制,且石油经过点都不需要任何花费。
图中有4类边。第一类为s到s’的边,其流量为A,费用为0;第二类为s’到xi的边,其容量为Bi,费用为Ci;第三类为xi到yj的边,其容量为Di,j,费用为Ei,j;第四类为yj到t的边,其容量为正无穷,费用为Fj。
Input
输入第一行有3个正整数,n,m,A,分别表示图中x类点的个数、y类点的个数和题目叙述中的A。
第二行有2n个正整数,第2i-1个数和第2i个数(1≤i≤n)表示题目中的Bi和Ci。
第三行有m个正整数,第j个数(1≤j≤m)表示题目中的Fj。
接下来n行,每行2m个正整数。第i行(1≤i≤n)第2j-1个数和第2j个数(1≤j≤m)分别表示Di,j和Ei,j。
Output
一行两个整数,最大的流量和流量最大时最小的费用。
Sample Input
3 2 3
3 2 2 1 10 2
1 1
3 2 3 3
1 1 3 2
10 4 10 5
Sample Output
3 12
Hint
每个测试点的数据规模如下
qwq ,数据太大 ,用费用流只有70分 ,先附上70分算法 。
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cstdio> 5 #include <queue> 6 const int inf = 1 << 30 , maxn = 2000 + 11 ;//1061109567 7 using namespace std ; 8 int n , m , val[maxn][maxn] , vol[maxn][maxn] , s , t , ans , dis[maxn] ; 9 bool mark[maxn] ; 10 queue< int > Q ; 11 12 inline void Init( ) 13 { 14 freopen( "NSOOJ#10829.in" , "r" , stdin ) ; 15 freopen( "NSOOJ#10829.out" , "w" , stdout ) ; 16 } 17 18 19 20 21 int read( ) { 22 char ch = getchar( ) ; int ret = 0 , k = 1 ; 23 while( ch < '0' || ch > '9' ) { if( ch == '-' ) k = -1 ; ch = getchar( ) ; } 24 while( ch >= '0' && ch <= '9' ) ret = ret * 10 + ch - '0' , ch = getchar( ) ; 25 return ret * k ; 26 } 27 28 void add( int u , int v , int va , int vo ) 29 { 30 val[u][v] = va ; vol[u][v] = vo ; 31 } 32 33 34 void input( ) 35 { 36 n = read( ) , m = read( ) ; 37 s = 0 , t = n + m + 2 ; 38 int a = read( ) , b ; 39 add( s , t - 1 , a , 0 ) ; add( t - 1 , s , 0 , 0 ) ; 40 for( int x = 1 ; x <= n ; ++x ) 41 { 42 a = read( ) ; b = read( ) ; 43 add( t-1 , x , a , b ) ; 44 add( x , t-1 , 0 , 0-b ) ; 45 } 46 for( int x = 1 ; x <= m ; ++x ) 47 { 48 a = read( ) ; 49 add( x+n , t , inf , a ) ; 50 add( t , x+n , 0 , 0-a ) ; 51 } 52 for( int x = 1 ; x <= n ; ++x ) 53 for( int y = 1 ; y <= m ; ++y ) 54 { 55 a = read( ) , b = read( ) ; 56 add( x , y+n , a , b ) ; 57 add( y+n , x , 0 , -b ) ; 58 } 59 } 60 61 bool spfa( ) 62 { 63 memset( mark , 0 , sizeof( mark ) ) ; 64 memset( dis , 127/2 , sizeof( dis ) ) ; 65 mark[t] = 1 , dis[t] = 0 ; Q.push( t ) ; 66 while( !Q.empty( ) ) 67 { 68 int u = Q.front( ) ; Q.pop( ) ; 69 for( int x = s ; x <= t ; x++ ) 70 { 71 if( val[x][u] && dis[u] + vol[x][u] < dis[x] ) 72 { 73 dis[x] = dis[u] + vol[x][u] ; 74 if( !mark[x] ) 75 { 76 Q.push( x ) ; 77 mark[x] = true ; 78 } 79 } 80 } 81 mark[u] = false ; 82 } //cout<<endl; 83 return dis[s] !=1061109567 ; 84 85 } 86 87 int dfs( int x , int f ) 88 { 89 mark[x] = true ; 90 if( x == t ) return f ; 91 int w , used = 0 ; 92 for( int v = 0 ; v <= t ; ++v ) 93 { 94 if( dis[v] == dis[x] - vol[x][v] && val[x][v] && !mark[v] ) 95 { 96 w = f - used ; 97 w = dfs( v , min( w , val[x][v] ) ) ; 98 ans += w * vol[x][v] ; 99 // cout<<w<<" "<<x<<" "<<v<<endl; 100 val[x][v] -= w , val[v][x] += w , used += w ; 101 if( used == f ) return f ; 102 } 103 } 104 return used ; 105 } 106 107 108 109 void zkw( ) 110 { 111 int sum = 0 ; 112 while( spfa( ) ) 113 { 114 mark[t] = 1 ; 115 while( mark[t] ) 116 { 117 memset( mark , 0 , sizeof( mark ) ) ; 118 sum += dfs( s , inf ) ; 119 } 120 } 121 122 printf( "%d %d " , sum , ans ) ; 123 } 124 125 126 127 int main ( ) 128 { 129 // Init( ) ; 130 input( ) ; 131 zkw( ) ; 132 // fclose( stdin ) ; 133 // fclose( stdout ) ; 134 return 0 ; 135 }
QwQ正确做法是贪心 ,望天 , 其实还是比较容易想出来的 , 就是将c[i],f[i]加到e[i][j]上去 ,然后排序每次选最少的 ,乘以可行的最大流量 ,然后将b[i]容量减了 ,就行了 ,qwq 。
1 #include <algorithm> 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <queue> 7 const int inf = 1 << 30 , maxn = 1000 + 11 ;//1061109567 8 using namespace std ; 9 struct id 10 { 11 int fro , to , val ; 12 } edge[maxn*maxn] ; 13 int n , m , tot , a , b[maxn] , c[maxn] , f[maxn] , d[maxn][maxn] , e[maxn][maxn] ; 14 15 inline void Init( ) 16 { 17 freopen( "NSOOJ#10829.in" , "r" , stdin ) ; 18 freopen( "NSOOJ#10829.out" , "w" , stdout ) ; 19 } 20 21 22 23 24 int read( ) { 25 char ch = getchar( ) ; int ret = 0 , k = 1 ; 26 while( ch < '0' || ch > '9' ) { if( ch == '-' ) k = -1 ; ch = getchar( ) ; } 27 while( ch >= '0' && ch <= '9' ) ret = ret * 10 + ch - '0' , ch = getchar( ) ; 28 return ret * k ; 29 } 30 31 void input( ) 32 { 33 n = read( ) , m = read( ) ; a = read( ) ; 34 for( int i = 1 ; i <= n ; ++i ) b[i] = read( ) , c[i] = read( ) ; 35 for( int i = 1 ; i <= m ; ++i ) f[i] = read( ) ; 36 for( int i = 1 ; i <= n ; ++i ) 37 for( int j = 1 ; j <= m ; ++j ) 38 { 39 d[i][j] = read( ) , e[i][j] = read( ) ; 40 edge[++tot] = (id) { i , j , c[i] + f[j] + e[i][j] } ; 41 } 42 } 43 44 int cmp( id a , id b ) { return a.val < b.val ; } 45 46 47 void sov( ) 48 { 49 sort( edge + 1 , edge + 1 + tot , cmp ) ; 50 int flow = a ; long long cost = 0 ; 51 for( int i = 1 ; i <= tot ; ++i ) 52 { 53 int f = min( flow , min(b[edge[i].fro] , d[edge[i].fro][edge[i].to] ) ) ; 54 flow -= f ; 55 b[edge[i].fro] -= f; 56 cost += 1ll * edge[i].val * f ; 57 } 58 printf( "%d %lld " , a - flow , cost ) ; 59 } 60 61 int main ( ) 62 { 63 // Init( ) ; 64 input( ) ; 65 sov( ) ; 66 // fclose( stdin ) ; 67 // fclose( stdout ) ; 68 return 0 ; 69 }