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

 

(完)

 

posted @ 2016-10-12 23:35  SHHHS  阅读(463)  评论(1编辑  收藏  举报