bzoj 3280(费用流)

12 篇文章 0 订阅

3280: 小R的烦恼

Time Limit: 10 Sec   Memory Limit: 512 MB
Submit: 307   Solved: 157
[ Submit][ Status][ Discuss]

Description

小R最近遇上了大麻烦,他的程序设计挂科了。于是他只好找程设老师求情。善良的程设老师答应不挂他,但是要求小R帮助他一起解决一个难题。
问题是这样的,程设老师最近要进行一项邪恶的实验来证明P=NP,这个实验一共持续n天,第i天需要a[i]个研究生来给他搬砖。研究生毕竟也是人,所以雇佣研究生是需要钱的,机智的程设老师已经联系好了m所大学,第j所大学共有l[j]个研究生,同时雇佣这所大学的一个研究生需要p[j]元钱。
本来程设老师满心欢喜的以为,这样捡最便宜的max{a[i]}个研究生雇来,就可以完成实验;结果没想到,由于他要求硕士生们每天工作25个小时不许吃饭睡觉上厕所喝水说话咳嗽打喷嚏呼吸空气,因此一天下来给他搬砖的所有研究生都会进入濒死状态。濒死状态的研究生,毫无疑问,就不能再进行工作了。但是机智的老师早早联系好了k家医院,第i家医院医治一个濒死的研究生需要d[i]天,并且需要q[i]元钱。

现在,程设老师想要知道,最少花多少钱,能够在这n天中满足每天的需要呢?若无法满足,则请输出”impossible”。注意,由于程设老师良心大大的坏,所以他是可以不把濒死的研究生送去医院的!

 
 

Input

       本题包含多组数据;第一行是一个数T(T<=11),表示数据组数,以下T组数据。
对于每一组数据,第一行三个数,n,m,k;
以下一行n个数,表示a[1]…a[n]
接着一行2m个数,表示l[1],p[1]…l[n],p[n]
接着一行2k个数,表示d[1],q[1]…d[n],q[n]

Output

       对于每组数据以样例的格式输出一行,两个数分别表示第几组数据和最少钱数。

Sample Input

2
3 2 1
10 20 30
40 90 15 100
1 5
3 2 1
10 20 30
40 90 15 100
2 5

Sample Output

Case 1: 4650
Case 2: impossible

HINT

样例解释:买下90块钱的那40个研究生,另外再买10个100块钱的。这样,第一天用完的10个人全部送到医院,那么他们在第三天可以继续使用;同时,第二天和第三天都用新的研究生来弥补,这样一共需要花费40*90 + 10*100 + 5*10 = 4650元。

数据规模:

对于30%的数据中的每组数据,

满足n<=5,m,k<=2,其余数均小于等于100或者 

n<=10,m,k<=10,其余数均小于等于20.

对于100%的数据

n,m,k<=50,其余数均小于等于100.


解题思路:与餐巾计划相同。简单建图

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define T 101
#define inf 0x7fffffff
using namespace std ;
inline int read ( )
{
     char ch = getchar ( ) ;
     int f = 1 , x = 0 ;
     while ( ! ( ch >= '0' && ch <= '9' ) ) { if ( ch == '-' ) f = - 1 ; ch = getchar ( ) ; }
     while ( ch >= '0' && ch <= '9' ) { x = x * 10 + ( ch - '0' ) ; ch = getchar ( ) ; }
     return x * f ;
}
int n , m , k , cnt , ans ;
int a [ 105 ] , q [ 105 ] , h [ 105 ] , head [ 105 ] , d [ 105 ] , from [ 105 ] ;
bool inq [ 105 ] ;
struct edge { int from , to , next , c , v ; } e [ 100001 ] ;
void ins ( int u , int v , int w , int c )
{
     e [ ++ cnt ] . from = u ; e [ cnt ] . to = v ;
     e [ cnt ] . next = head [ u ] ; head [ u ] = cnt ;
     e [ cnt ] . c = c ; e [ cnt ] . v = w ;
}
void insert ( int u , int v , int w , int c )
{ ins ( u , v , w , c ) ; ins ( v , u , 0 , - c ) ; }
bool spfa ( )
{
     for ( int i = 0 ; i <= T ; i ++ ) d [ i ] = inf ;
     int t = 0 , w = 1 ; d [ 0 ] = 0 ; inq [ 0 ] = 1 ; q [ 0 ] = 0 ;
     while ( t != w )
     {
         int now = q [ t ] ; t ++ ; if ( t == T ) t = 0 ;
         for ( int i = head [ now ] ; i ; i = e [ i ] . next )
             if ( e [ i ] . v && d [ e [ i ] . to ] > d [ now ] + e [ i ] . c )
             {
                 d [ e [ i ] . to ] = d [ now ] + e [ i ] . c ; from [ e [ i ] . to ] = i ;
                 if ( ! inq [ e [ i ] . to ] )
                 { inq [ e [ i ] . to ] = 1 ; q [ w ++ ] = e [ i ] . to ; if ( w == T ) w = 0 ; }
             }
         inq [ now ] = 0 ;
     }
     if ( d [ T ] == inf ) return 0 ;
     return 1 ;
}
void mcf ( )
{
     int x = inf ;
     for ( int i = from [ T ] ; i ; i = from [ e [ i ] . from ] )
         x = min ( x , e [ i ] . v ) ;
     for ( int i = from [ T ] ; i ; i = from [ e [ i ] . from ] )
         { e [ i ] . v -= x ; e [ i ^ 1 ] . v += x ; ans += e [ i ] . c * x ; }
}
int main ( )
{
     int x , y , test = read ( ) ;
     for ( int l = 1 ; l <= test ; l ++ )
     {
         printf ( "Case %d: " , l ) ;
         cnt = 1 ; ans = 0 ;
         memset ( head , 0 , sizeof ( head ) ) ;
         n = read ( ) ; m = read ( ) ; k = read ( ) ;
         for ( int i = 1 ; i <= n ; i ++ )
         {
             a [ i ] = read ( ) ;
             insert ( i , T , a [ i ] , 0 ) ;
             insert ( 0 , i + n , a [ i ] , 0 ) ;
             if ( i < n ) insert ( i , i + 1 , inf , 0 ) ;
         }
         for ( int i = 1 ; i <= m ; i ++ )
         {
             x = read ( ) ; y = read ( ) ;
             insert ( 0 , 1 , x , y ) ;
         }
         for ( int i = 1 ; i <= k ; i ++ )
         {
             x = read ( ) ; y = read ( ) ;
             for ( int j = 1 ; j <= n ; j ++ )
                 if ( j + x + 1 <= n ) insert ( n + j , j + x + 1 , inf , y ) ;
         }
         while ( spfa ( ) ) mcf ( ) ;
         bool f = 0 ;
         for ( int i = 2 ; i <= cnt ; i += 2 )
           if ( e [ i ] . to == T && e [ i ] . v ) { printf ( "impossible\n" ) ; f = 1 ; break ; }
         if ( ! f ) printf ( "%d\n" , ans ) ;
     }
     return 0 ;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值