POJ 2227 The Wedding Juicer

    http://acm.pku.edu.cn/JudgeOnline/problem?id=2227

    《算法艺术与信息学竞赛》一书例题(p89) , 挺不错的一道题。

    能存储的水的量主要取决于最低的位置的高度,而且边缘是不能注水的。所以可以从边缘中找出一个最低点,然后对其四周进行操作,有两种情况:

    1、旁边的格子高度比其大,这个时候就要将这个格子标记为不能注水,如果注水,则会流出,这个格子旁边的格子若比他大也需标记不能注水

    2、旁边的格子高度比其小,此时可以注入水达到两个格子的水量相同,由于我们事先选取了最低的格子,所以这个水必定不会流出,同理还要对这个水周围比其高度大的格子进行标志。

    由于每次都需要找最低的格子进行覆盖,所以要用到优先队列来进行优化,由于每个格子最多进队一次,所以时间复杂度为O( nmlog(nm) )

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
1 #include < iostream >
2 #include < queue >
3 #include < vector >
4 #include < algorithm >
5   using namespace std;
6
7 const int maxn = 301 ;
8
9 typedef __int64 LL;
10
11 int W, H, hash[maxn][maxn];
12 LL bowl[maxn][maxn], A , B;
13 struct NODE { LL r, c, h; } T;
14
15 struct cmp {
16 bool operator () ( const NODE a, const NODE b) const {
17 return a.h > b.h;
18 }
19 };
20 priority_queue < NODE , vector < NODE > , cmp > que;
21
22 int move[ 4 ][ 2 ] = { { 1 , 0 }, { - 1 , 0 }, { 0 , 1 }, { 0 , - 1 } };
23
24 void cover(LL r , LL c, LL h) // 覆盖周围比其高的格子
25 {
26 for ( int i = 0 ; i < 4 ; i ++ ) {
27 LL x = r + move[i][ 0 ];
28 LL y = c + move[i][ 1 ];
29 if (x <= 0 || y <= 0 || x > H || y > W || hash[x][y] || bowl[x][y] < h)
30 continue ;
31 NODE tmp;
32 tmp.r = x , tmp.c = y , tmp.h = bowl[x][y];
33 hash[x][y] = 1 ;
34 que.push( tmp );
35 cover(x , y , tmp.h);
36 }
37 }
38
39 void floodfill(LL r , LL c, LL h) // 注入水
40 {
41 for ( int i = 0 ; i < 4 ; i ++ ) {
42 LL x = r + move[i][ 0 ];
43 LL y = c + move[i][ 1 ];
44 if (x <= 0 || y <= 0 || x > H || y > W || hash[x][y] || bowl[x][y] > h)
45 continue ;
46 NODE tmp;
47 tmp.r = x , tmp.c = y , tmp.h = h;
48 bowl[x][y] = h;
49 hash[x][y] = 1 ;
50 que.push( tmp );
51 floodfill(x , y , h);
52 cover(x , y , h);
53 }
54 }
55
56 void init() // 初始将边缘不能注水的格子推入优队
57 {
58 for ( int i = 1 ; i <= W; i ++ )
59 {
60 T.r = 1 , T.c = i , T.h = bowl[ 1 ][i];
61 hash[ 1 ][i] = 1 ;
62 que.push(T);
63 T.r = H , T.c = i , T.h = bowl[H][i];
64 hash[H][i] = 1 ;
65 que.push(T);
66 }
67
68 for ( int i = 1 ; i <= H; i ++ )
69 {
70 T.r = i , T.c = 1 , T.h = bowl[i][ 1 ];
71 hash[i][ 1 ] = 1 ;
72 que.push(T);
73 T.r = i , T.c = W , T.h = bowl[i][W];
74 hash[i][W] = 1 ;
75 que.push(T);
76 }
77 }
78
79 void solve()
80 {
81 LL r , c , h;
82 while ( ! que.empty())
83 {
84 r = que.top().r , c = que.top().c , h = que.top().h , que.pop();
85 floodfill( r , c , h );
86 cover( r , c , h );
87 }
88 for ( int i = 1 ; i <= H; i ++ )
89 for ( int j = 1 ; j <= W; j ++ )
90 B += bowl[i][j];
91 printf( " %I64d\n " , B - A);
92 }
93
94 int main()
95 {
96 A = B = 0 ;
97 scanf( " %d %d " , & W, & H);
98 for ( int i = 1 ; i <= H; i ++ ) {
99 for ( int j = 1 ; j <= W; j ++ ) {
100 scanf( " %I64d " , & bowl[i][j]);
101 A += bowl[i][j];
102 }
103 }
104 init();
105 solve();
106 return 0 ;
107 }
108

 

转载于:https://www.cnblogs.com/xiao_wu/archive/2010/05/23/1741863.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值