首页 > 代码库 > BZOJ 1001 题解

BZOJ 1001 题解

1001: [BeiJing2006]狼抓兔子

Time Limit: 15 Sec  Memory Limit: 162 MB
Submit: 18876  Solved: 4649
[Submit][Status][Discuss]

Description

现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:

 技术分享

左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 
1:(x,y)<==>(x+1,y) 
2:(x,y)<==>(x,y+1) 
3:(x,y)<==>(x+1,y+1) 
道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的. 左上角和右下角为兔子的两个窝,开始时所有的兔子都聚集在左上角(1,1)的窝里,现在它们要跑到右下解(N,M)的窝中去,狼王开始伏击这些兔子.当然为了保险起见,如果一条道路上最多通过的兔子数为K,狼王需要安排同样数量的K只狼,才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的狼的数量要最小。因为狼还要去找喜羊羊麻烦.

Input

第一行为N,M.表示网格的大小,N,M均小于等于1000.
接下来分三部分
第一部分共N行,每行M-1个数,表示横向道路的权值. 
第二部分共N-1行,每行M个数,表示纵向道路的权值. 
第三部分共N-1行,每行M-1个数,表示斜向道路的权值. 
输入文件保证不超过10M

Output

输出一个整数,表示参与伏击的狼的最小数量.

Sample Input

3 4
5 6 4
4 3 1
7 5 3
5 6 7 8
8 7 6 5
5 5 5
6 6 6

Sample Output

14

HINT

Source

——————————————————分割线——————————————————

这道题是一道很玄学的题目,我们不能直接求它的最小割,要通过它的对偶图的最短路。那么怎么完成呢?

技术分享

技术分享

这时,只需求点1到点14的最短路就行啦。

[ATTENTION]:这道题点数总共有( N - 1 ) * ( M - 1) * 2 + 2 个,本蒟蒻被坑了好久。注意数组大小!!!

推荐一个课件:浅析最大最小定理在信息学竞赛中的应用

技术分享
 1 /************************************************************** 2     Problem: 1001 3     User: shadowland 4     Language: C++ 5     Result: Accepted 6     Time:2752 ms 7     Memory:165356 kb 8 ****************************************************************/ 9 10 #include "bits/stdc++.h"11   12 using namespace std ;13 struct Edge { int to , next , val ; } ;14 const int maxN = 8000100 ;15   16 Edge e[ maxN ] ;17 int head[ maxN ] , Dis[ maxN ] ;18 bool vis[ maxN ] ;19   20 int N , M , cnt ;21  22 inline int INPUT ( ) {23         int x = 0 , f = 1 ; char ch = getchar ( ) ;24         while ( ch < 0 || ch > 9 ) { if ( ch == -)f = -1 ; ch = getchar ( ) ;}25         while ( ch >= 0 && ch <= 9 ) { x = ( x << 1 ) + ( x << 3 ) + ch - 0 ; ch = getchar ( ) ;}26         return x * f ;  27 } 28  29 inline int Get ( const int x , const int y , const int z ) {30         if ( x < 1 || y >=M ) return ( N - 1 ) * ( M - 1 ) * 2 + 2 ;31         if ( x >= N || y < 1 ) return 1 ;32         return ( ( x - 1 ) * ( M - 1 ) + y ) *2 + z ;33 } 34   35 inline void Add_Edge ( const int x , const int y , const int _val ) {36         e[ ++cnt ].to = y ;37         e[ cnt ].val = _val ;38         e[ cnt ].next = head[ x ] ;39         head[ x ] = cnt ;40 }41   42 void SPFA ( const int S ) {43         memset ( vis , false , sizeof ( vis ) ) ;44         memset ( Dis , 0x3f , sizeof ( Dis ) ) ;45         queue < int > Q ; 46         Dis[ S ] = 0 ;47         vis[ S ] = true ;48         Q.push ( S ) ;49         while ( !Q.empty ( ) ) {50                 int t = Q.front( ) ; Q.pop ( ) ; vis[ t ] = false ;51                 for ( int i=head[ t ] ; i ; i = e[ i ].next ) {52                         int temp = e[ i ].to ;53                         if ( Dis[ temp ] > Dis[ t ] + e[ i ].val ) {54                                 Dis[ temp ] = Dis[ t ] + e[ i ].val ;55                                 if ( !vis[ temp ] ) {56                                         Q.push ( temp ) ;57                                         vis[ temp ] = true ;58                                 }59                         }60                 }61         }62 }63   64 void DEBUG_ ( int N , int M ) {65         printf ( "\n" ) ;66         for ( int i=1 ; i<=(( N - 1 ) * ( M - 1 ) * 2 + 2) ; ++i ) {67                 printf ( "%d " , Dis[ i ] ) ;68         }69 }70 int main ( ) {71         int _val ; 72         scanf ( "%d %d" , &N , &M ) ;73         for ( int i=1 ; i<=N ; ++i ) {74                 for ( int j=1 ; j<M ; ++j ) {75                         _val = INPUT ( ) ;76                         Add_Edge ( Get ( i , j , 1 ) , Get ( i - 1 , j , 0 ) , _val ) ;77                         Add_Edge ( Get ( i - 1 , j , 0 ) , Get ( i , j , 1 ) , _val ) ;78                 }79         }80         for ( int i=1 ; i<N ; ++i ) {81                 for ( int j=1 ; j<=M ; ++j ) {82                         _val = INPUT ( ) ;83                         Add_Edge ( Get ( i , j - 1 , 1 ) , Get ( i , j , 0 ) , _val ) ;84                         Add_Edge ( Get ( i , j , 0 ) , Get ( i , j - 1 , 1 ) , _val ) ;85                 }86         }87         for ( int i=1 ; i<N ; ++i ) {88                 for ( int j=1 ; j<M ; ++j ) {89                         _val = INPUT ( ) ;90                         Add_Edge ( Get ( i , j , 0 ) , Get ( i , j , 1 ) , _val ) ;91                         Add_Edge ( Get ( i , j , 1 ) , Get ( i , j , 0 ) , _val ) ;92                 }93         }94         SPFA ( 1 ) ;95         printf ( "%d\n" , Dis[ ( N - 1 ) * ( M - 1 ) * 2 + 2 ] ) ;96         //DEBUG_( N , M ) ;97           98         return 0 ;99 } 
View Code

 

2016-10-12 23:35:00

 

(完)

 

BZOJ 1001 题解