网络流24题 洛谷 4015 运输问题

#include <bits/stdc++.h>

const  int  N = 500 + 5 ;

std :: queue < int >  q ;

int  head [ N << 8 ] , nxt [ N << 8 ] , flt [ N << 8 ] , dis [ N << 8 ] , to [ N << 8 ] , cn = 1 ;
int  pree [ N ] , pred [ N ] , c [ N ] , inf , src , sink , n , m , maxcost , mincost , ck [ N ] , ls [ N ] ;
int  x [ N ] [ N ] ; 
bool  vis [ N ] ; 

void  create ( int  u , int  v , int  f , int  d ) {
	cn ++ ;
	to [ cn ] = v ;
	dis [ cn ] = d ;
	flt [ cn ] = f ;
	nxt [ cn ] = head [ u ] ;
	head [ u ] = cn ;
	
	cn ++ ;
	to [ cn ] = u ; 
	dis [ cn ] = - d ;
	flt [ cn ] = 0 ;
	nxt [ cn ] = head [ v ] ;
	head [ v ] = cn ; 
} 

void  prp ( ) {
	int  o [ 5 ] ;
	memset ( o , 127 , sizeof ( o ) ) ;
	inf =  o [ 0 ] ;
}

bool  spfa1 ( ) {
	memset ( pree , 0 , sizeof ( pree ) ) ;
	memset ( pred , 0 , sizeof ( pred ) ) ;
	memset ( vis , false , sizeof ( vis ) ) ;
	memset ( c , 127 , sizeof ( c ) ) ;
	q . push ( src ) ;
	c [ src ] = 0 ;
	vis [ src ] = true ;
	while ( ! q . empty ( ) ) {
		int  tmp = q . front ( ) ; q . pop ( ) ;
		vis [ tmp ] = false ;
		for ( int  i = head [ tmp ] ; i ; i = nxt [ i ] ) {
			int  v = to [ i ] ;
			if ( flt [ i ]  &&  c [ v ] > c [ tmp ] + dis [ i ] ) {
				c [ v ] = c [ tmp ] + dis [ i ] ;
				pree [ v ] = i ;
				pred [ v ] = tmp ;
				if ( ! vis [ v ] ) {
					vis [ v ] = true ;
					q . push ( v ) ;
				}
			}
		}
	}
	return  c [ sink ] < inf ;
} 

bool  spfa2 ( ) {
	memset ( pree , 0 , sizeof ( pree ) ) ;
	memset ( pred , 0 , sizeof ( pred ) ) ;
	memset ( vis , false , sizeof ( vis ) ) ;
	memset ( c , 128 , sizeof ( c ) ) ;
	q . push ( src ) ;
	c [ src ] = 0 ;
	vis [ src ] = true ;
	while ( ! q . empty ( ) ) {
		int  tmp = q . front ( ) ; q . pop ( ) ;
		vis [ tmp ] = false ;
		for ( int  i = head [ tmp ] ; i ; i = nxt [ i ] ) {
			int  v = to [ i ] ;
			if ( flt [ i ]  &&  c [ v ] < c [ tmp ] + dis [ i ] ) {
				c [ v ] = c [ tmp ] + dis [ i ] ;
				pree [ v ] = i ;
				pred [ v ] = tmp ;
				if ( ! vis [ v ] ) {
					vis [ v ] = true ;
					q . push ( v ) ;
				}
			}
		}
	}
	return  c [ sink ] > - inf ;
} 

void  augment1 ( ) {
	int  u = sink , delta = inf , sum = 0 ;
	while ( u != src ) {
		if ( delta > flt [ pree [ u ] ] )
			 delta = flt [ pree [ u ] ] ;
		u = pred [ u ] ;
	}
	u = sink ;
	while ( u != src ) {
		flt [ pree [ u ] ] -= delta ;
		flt [ pree [ u ] ^ 1 ] += delta ;
		sum += delta * dis [ pree [ u ] ] ;
		u = pred [ u ] ;
	}
	mincost += sum ;
}

void  augment2 ( ) {
	int  u = sink , delta = inf , sum = 0 ;
	while ( u != src ) {
		if ( delta > flt [ pree [ u ] ] )
			 delta = flt [ pree [ u ] ] ;
		u = pred [ u ] ;
	}
	u = sink ;
	while ( u != src ) {
		flt [ pree [ u ] ] -= delta ;
		flt [ pree [ u ] ^ 1 ] += delta ;
		sum += delta * dis [ pree [ u ] ] ;
		u = pred [ u ] ;
	}
	maxcost += sum ;
}

void  init ( ) {
	memset ( head , 0 , sizeof ( head ) ) ;
	memset ( flt , 0 , sizeof ( flt ) ) ;
	memset ( nxt , 0 , sizeof ( nxt ) ) ;
	memset ( dis , 0 , sizeof ( dis ) ) ;
	memset ( to , 0 , sizeof ( to ) ) ;
}

int  main ( ) {
	scanf ( "%d%d" , & n , & m ) ;
	prp ( ) ; 
	src = 0 ; sink = n + m + 1 ;
	
	for ( int  i = 1 ; i <= n ; i ++ ) 
		scanf ( "%d" , & ck [ i ] ) ;
	for ( int  i = n + 1 ; i <= n + m ; i ++ )
		scanf ( "%d" , & ls [ i ] ) ;
	for ( int  i = 1 ; i <= n ; i ++ )
		for ( int  j = n + 1 ; j <= m + n ; j ++ ) {
			scanf ( "%d" , & x [ i ] [ j ] ) ;
			create ( i , j , inf , x [ i ] [ j ] ) ;
		}
	for ( int  i = 1 ; i <= n ; i ++ )
		create ( src , i , ck [ i ] , 0 ) ;
	for ( int  i = n + 1 ; i <= n + m ; i ++ )
		create ( i , sink , ls [ i ] , 0 ) ;
	while ( spfa1 ( ) )
		augment1 ( ) ;
	init ( ) ;
	
	
	for ( int  i = 1 ; i <= n ; i ++ )
		for ( int  j = n + 1 ; j <= m + n ; j ++ )
			create ( i , j , inf , x [ i ] [ j ] ) ;
	for ( int  i = 1 ; i <= n ; i ++ )
		create ( src , i , ck [ i ] , 0 ) ;
	for ( int  i = n + 1 ; i <= n + m ; i ++ )
		create ( i , sink , ls [ i ] , 0 ) ;
	
	while ( spfa2 ( ) ) 
		augment2 ( ) ;
	
	printf ( "%d\n%d" , mincost , maxcost ) ;
	return  0 ; 
}
裸题
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值