[HNOI2013]切糕

题目链接CodeVS2297

题目大意
把一个( X×Y×Z , 其中 X,Y,Z40 ) 的切糕切成上下两半,且对于每一对(x,y),都有 1f(x,y)Z
满足条件:
1. x,yV(x,y,f(x,y)) 最小 ;
2. 对于每一对( x1,y1 )和( x2,y2 ),( |f1f2|D ) 。

分析
啥?分成上下两份?最小割啊!!!
1. 对每一个点( x,y,z ),变成一个容量为 v(x,y,z) 的边(即向上连一条边,因此要在顶层的上面再加一层)。
2. 对每个点,向( x,y,zD )的周围四个点连容量为INF 的边( 保证不能跨D格的高度割)。
3. 为什么只能向( zD )连而不能向( z+D )连 ? 因为向上连边会使最大流增大!
4. 超级源S向所有第一层的点连边(INF),超级汇T向所有的最最上层连边(INF)。
5. 直接把所有的点放在一起跑最大流–最小割。

PS.换了一个更快的代码

上代码

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

const int N = 40 + 5 ;
const int M = 32e4 + 5 ;
const int INF = 0x3f3f3f3f ;
const int DIR[ 4 ][ 2 ] = { { -1 , 0 } , { 1 , 0 } , { 0 , 1 } , { 0 , -1 } } ;

int lx, ly, lz, D ;

// ID把三维点映射到一维
#define ID( x , y , z ) ( (z) * lx * ly + (y) * lx + (x) )
struct node {
    int x, y, z, id ;
    inline bool judge() {
        return x >= 1 && x <= lx && y >= 1 && y <= ly && z >= 1 && z <= lz ;
    }
    inline node move( int a , int b , int c ) {
        node temp = (node){ x + a , y + b , z + c , 0 } ;
        temp.id = ID( temp.x , temp.y , temp.z ) ;
        return temp ;
    }
} S, T ;

int head[ N * N * N ], len ;
struct node_lib {
    int to, val, next ;
    inline void add( int a , int b , int c ) {
        to = b, val = c ;
        next = head[ a ], head[ a ] = len ++ ;
    }
} lib[ M << 1 ] ;

inline void init() {
    memset( head , 0xff , sizeof( head ) ) ;
    scanf( "%d %d %d %d", &lx, &ly, &lz, &D ) ;
    S = (node){ 0 , 0 , 0 , ID( 0 , 0 , 0 ) } ;
    T = (node){ 0 , 0 , lz + 2 , ID( 0 , 0 , lz + 2 ) } ;
    for ( int z = 1 ; z <= lz ; z ++ )
        for ( int x = 1 ; x <= lx ; x ++ )
            for ( int y = 1 ; y <= ly ; y ++ ) {
                int a ; scanf( "%d", &a ) ; // 建图
                node temp = (node){ x , y , z , ID( x , y , z ) } ;
                node nown = temp.move( 0 , 0 , 1 ) ;
                lib[ len ].add( temp.id , nown.id , a ) ;
                lib[ len ].add( nown.id , temp.id , 0 ) ;
                if ( z - D > 0 )
                    for ( int i = 0 ; i < 4 ; i ++ ) {
                        nown = temp.move( DIR[ i ][ 0 ] , DIR[ i ][ 1 ] , -D ) ;
                        if ( !nown.judge() )    continue ;
                        lib[ len ].add( temp.id , nown.id , INF ) ;
                        lib[ len ].add( nown.id , temp.id , 0 ) ;
                    }
            }
    for ( int x = 1 ; x <= lx ; x ++ )
        for ( int y = 1 ; y <= ly ; y ++ ) {
            node tmp1 = (node){ x , y , 1 , ID( x , y , 1 ) } ;
            node tmp2 = (node){ x , y , lz + 1 , ID( x , y , lz + 1 ) } ;
            lib[ len ].add( S.id , tmp1.id , INF ) ;
            lib[ len ].add( tmp1.id , S.id , 0 ) ;
            lib[ len ].add( tmp2.id , T.id , INF ) ;
            lib[ len ].add( T.id , tmp2.id , 0 ) ;
        }
}

// 以下是模板
queue < int > Q ;
int curn[ N * N * N ] ;
int step[ N * N * N ] ;
inline bool bfs() {
    memset( step , 0 , sizeof( step ) ) ;
    step[ S.id ] = 1 ; Q.push( S.id ) ;
    while ( !Q.empty() ) {
        int temp = Q.front() ; Q.pop() ;
        for ( int p = head[ temp ] ; ~ p ; p = lib[ p ].next ) {
            int nown = lib[ p ].to ;
            if ( !step[ nown ] && lib[ p ].val ) {
                step[ nown ] = step[ temp ] + 1 ; Q.push( nown ) ;
            }
        }
    }
    if ( step[ T.id ] ) return true ;
    else    return false ;
}
int dfs( int a , int b ) {
    if ( a == T.id )    return b ;
    for ( int &p = curn[ a ] ; ( ~ p ) && b ; p = lib[ p ].next ) {
        int nown = lib[ p ].to ;
        if ( step[ nown ] == step[ a ] + 1 && lib[ p ].val ) {
            int temp = dfs( nown , min( b , lib[ p ].val ) ) ;
            if ( temp ) {
                lib[ p ].val -= temp ; lib[ p ^ 1 ].val += temp ;
                return temp ;
            }
        }
    }
    return 0 ;
}
inline int figure() {
    int ans = 0 ;
    while ( bfs() ) {
        for ( int x = 1 ; x <= lx ; x ++ )
            for ( int y = 1 ; y <= ly ; y ++ )
                for ( int z = 1 ; z <= lz + 1 ; z ++ ) {
                    int id = ID( x , y , z ) ;
                    curn[ id ] = head[ id ] ;
                }
        curn[ S.id ] = head[ S.id ], curn[ T.id ] = head[ T.id ] ;
        while ( int temp = dfs( S.id , INF ) )
            ans += temp ;
    }
    return ans ;
}

int main() {
    init() ;
    printf( "%d\n", figure() ) ;
    return 0 ;
}

以上

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值