JZOJ4716. 飞扬的小鸟

来源:互联网 发布:淘宝两个店铺绑定 编辑:程序博客网 时间:2024/05/01 18:02

原题:NOI2012美食节

题目大意

n种体型的小鸟,一共有m个洞,第i种体型的小鸟有pi只,穿过第j个洞需要T(i,j)的时间。每个小鸟都要等前面穿过同一个洞的鸟通过后才能通过。求最少的总等待时间。

Data Constraint
n40,m100,pi800,T(i,j)1000

题解

对于一个洞j,最后一只通过的鸟i对答案的贡献为T(i,j),倒数第二只贡献为2T(i,j),其余以此类推。
考虑费用流,记(Flow,Cost)表示一条流量为Flow费用为Cost的边:

  • S向每个种类的鸟连(pi,0)
  • 每个洞拆成pi个点,每个种类的鸟先这些点连边(1,kT(i,j))
  • 每个洞向T(1,0)

边数比较多,所以要用动态加边。

SRC

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>#include<queue>using namespace std ;#define N 100 + 10#define M 100000 + 10typedef long long ll ;bool flag[N][10*N] , vis[M] ;int Node[2*M] , Next[2*M] , C[2*M] , Cost[2*M] , Head[M] , tot = 1 ;int D[10*M] , Dist[M] , Pre[M] , Rec[2*M] , Bel[2*M] ;int Tim[N][N] , p[N] ;int n , m , S , T , SumP ;ll ans ;void link( int u , int v , int w , int fee ) {    Node[++tot] = v , Next[tot] = Head[u] , C[tot] = w , Cost[tot] = fee , Head[u] = tot ;    Node[++tot] = u , Next[tot] = Head[v] , C[tot] = 0 , Cost[tot] = -fee , Head[v] = tot ;}bool SPFA() {    memset( vis , 0 , sizeof(vis) ) ;    memset( Dist , 63 , sizeof(Dist) ) ;    int i = 0 , j = 1 ;    D[1] = S ;    Dist[S] = 0 ;    vis[S] = 1 ;    while ( i < j ) {        i ++ ;        int now = D[i] ;        for (int p = Head[now] ; p ; p = Next[p] ) {            if ( !C[p] ) continue ;            if ( Dist[now] + Cost[p] < Dist[Node[p]] ) {                Dist[Node[p]] = Dist[now] + Cost[p] ;                Pre[Node[p]] = p ;                if ( !vis[Node[p]] ) {                    vis[Node[p]] = 1 ;                    D[++j] = Node[p] ;                    if ( Dist[D[i+1]] > Dist[D[j]] ) swap( D[i+1] , D[j] ) ;                }            }        }        vis[now] = 0 ;    }    return Dist[T] < Dist[T+1] ;}int main() {    freopen( "bird.in" , "r" , stdin ) ;    freopen( "bird.out" , "w" , stdout ) ;    scanf( "%d%d" , &n , &m ) ;    for (int i = 1 ; i <= n ; i ++ ) {        scanf( "%d" , &p[i] ) ;        SumP += p[i] ;    }    S = 0 , T = n + SumP * m + 1 ;    for (int i = 1 ; i <= n ; i ++ ) {        link( S , i , p[i] , 0 ) ;        for (int j = 1 ; j <= m ; j ++ ) {            scanf( "%d" , &Tim[i][j] ) ;        }    }    for (int j = 1 ; j <= m ; j ++ ) {        link( n + j , T , 1 , 0 ) ;        for (int i = 1 ; i <= n ; i ++ ) {            link( i , n + j , 1 , Tim[i][j] ) ;            Bel[tot^1] = j ;            Rec[tot^1] = 0 ;        }    }    while ( SPFA() ) {        int Minv = 0x7FFFFFFF ;        for (int x = T ; x != S ; x = Node[Pre[x]^1])            Minv = min( Minv , C[Pre[x]] ) ;        ans += Dist[T] * Minv ;        for (int x = T ; x != S ; x = Node[Pre[x]^1]) {            C[Pre[x]] -= Minv ;            C[Pre[x]^1] += Minv ;            if ( Bel[Pre[x]] ) {                int j = Bel[Pre[x]] ;                int k = Rec[Pre[x]] + 1 ;                if ( flag[j][k] || k >= SumP ) continue ;                flag[j][k] = 1 ;                int now = n + m * k + j ;                link( now , T , 1 , 0 ) ;                for (int i = 1 ; i <= n ; i ++ ) {                    link( i , now , 1 , Tim[i][j] * (k + 1) ) ;                    Bel[tot^1] = j ;                    Rec[tot^1] = k ;                }            }        }    }    printf( "%lld\n" , ans ) ;    return 0 ;}

以上.

1 0