[BZOJ1280]-Emmy卖猪pigs-网络流

版权声明:转载嘛....也不是不可以(故作沉思),记得带上me的ID啊qwq https://blog.csdn.net/Izumi_Hanako/article/details/80685378

说在前面

me终于要想到网络流了!!!然后耐心没了…
然后就去看了题解
喵喵喵喵喵????


题目

BZOJ1280传送门
看题可戳传送门


解法

首先我们发现这是一个分配问题
分配问题一般有两种解法,第一种是网络流,第二种是倒着dp(有时候分配问题倒过来就是需求问题,就可以用dp解决)
这个题me发现,正着/倒着都没办法转化成需求问题。
然后me想,这个题的分配关系是有拓扑序的,应该可以建个图跑跑
然后me就去看了题解

那么对于这个题,我们可以建出一个比较显然的网络流图:
把每个人的购买操作看成时间轴,并把猪圈拆点
每个时间的猪圈 都向 下个时间的猪圈 连边;人连汇点;源点连起始猪圈;当前人可购买的猪圈,向人连边,人向下一个时间的这些猪圈连边

然后我们发现这个图,很多inf边,于是我们考虑把没有用的点全部去掉。最后就剩下了人和人连边:对于第i个猪圈,上一个来这里的人 向 下一个来这里的人 连边inf。如果是第一个来的,S向其连 猪圈大小 的边

理解一下这个图,相当于是 每个人 实际上就是一个「调度站」,下一个人如果需要,那么这次开门的时候,就放一些pig进去给下一个人。不难发现这是正确的

(感觉这个建图还蛮有意思的)


下面是代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;

bool acce[105][105] ;
int N , M , head[105] , tp = 1 , a[1005] , pre[1005] ;
int S , T ;
struct Path{
    int pre , to , flow ;
} p[22005] ;

void In( int t1 , int t2 , int t3 ){
    p[++tp] = ( Path ){ head[t1] , t2 , t3 } ; head[t1] = tp ;
    p[++tp] = ( Path ){ head[t2] , t1 , 0 } ; head[t2] = tp ;
}

int que[105] , fr , ba , dis[105] ;
bool BFS(){
    memset( dis , -1 , sizeof( dis ) ) ;
    fr = 1 , que[ ba = 1 ] = S , dis[S] = 0 ;
    while( ba >= fr ){
        int u = que[fr++] ;
        for( int i = head[u] ; i ; i = p[i].pre ){
            int v = p[i].to ;
            if( !p[i].flow || dis[v] != -1 ) continue ;
            dis[v] = dis[u] + 1 , que[++ba] = v ;
        }
    } return dis[T] != -1 ;
}

int dfs( int u , int flow ){
    if( u == T ) return flow ;
    int rt = 0 ;
    for( int i = head[u] ; i ; i = p[i].pre ){
        int v = p[i].to , nowf ;
        if( dis[v] != dis[u] + 1 || !p[i].flow ) continue ;
        if( ( nowf = dfs( v , min( p[i].flow , flow ) ) ) ){
            p[i].flow -= nowf , p[i^1].flow += nowf ;
            flow -= nowf , rt += nowf ;
        }
    } if( flow ) dis[u] = -1 ;
    return rt ;
}

void solve(){
    int ans = 0 ;
    while( BFS() )
        ans += dfs( S , 0x3f3f3f3f ) ;
    printf( "%d" , ans ) ;
}

int main(){
    scanf( "%d%d" , &M , &N ) , S = N + 1 , T = N + 2 ;
    for( int i = 1 ; i <= M ; i ++ ) scanf( "%d" , &a[i] ) ;

    for( int i = 1 , c ; i <= N ; i ++ ){
        scanf( "%d" , &c ) ;
        for( int j = 1 , t ; j <= c ; j ++ ){
            scanf( "%d" , &t ) ;
            if( !pre[t] ) In( S , i , a[t] ) ;
            else acce[ pre[t] ][i] = true ;
            pre[t] = i ;
        } scanf( "%d" , &c ) , In( i , T , c ) ;
    }
    for( int i = 1 ; i <= N ; i ++ )
        for( int j = 1 ; j <= N ; j ++ )
            if( acce[i][j] ) In( i , j , 0x3f3f3f3f ) ;
    solve() ;
}

猜你喜欢

转载自blog.csdn.net/Izumi_Hanako/article/details/80685378