BZOJ 1001 题解
1001: [BeiJing2006]狼抓兔子
Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 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
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 }
2016-10-12 23:35:00
(完)