1. 程式人生 > >花神倒果汁

花神倒果汁

-o 還要 get 其他 規則 決定 proc ons bsp

花神倒果汁
(juice.pas/c/cpp)
【題目描述】
為了慶祝花神開花,花神決定舉辦一個宴會。其中有一個遊戲叫倒果汁。
果汁容器的底座是一個獨立的N×M的矩陣,矩陣的每個格點有一個高度,表示這個格子正上方有多少個1×1×1的方塊。相鄰兩個方塊被粘得嚴實,不會漏。
現在花神給你一盒果汁,問你在不使果汁滿出來的情況下,容器最多能裝下多少立方單位的果汁。
【輸入格式】
第一行兩個整數N和M。
接下來M行,每行N個整數,表示這個格子的高度H[i][j]。
【輸出格式】
僅一行,表示答案。
【樣例輸入】
4 5
5 8 7 7
5 2 1 5
7 1 7 1
8 9 6 9
9 8 9 9

【樣例輸出】
12

【樣例解釋】
矩陣變成了:
5 8 7 7
5 5 5 5
7 5 7 1
8 9 7 9
9 8 9 9
3+4+4+1=12
【數據規模】
對於100%的數據:1≤M,N≤300;H[i][j]≤10^9;

這題就是著名的“短板效應”——一個木桶裏的水最多能裝多少取決於其最短的一條版高度是多少。那麽,我們自然可以把外面四周邊界看作木桶的“板”。我們要想在裏面裝水,我們自然要知道這最短的一根版。但因為題目中說“相鄰兩個方塊被粘得嚴實,不會漏”,那麽最角落的4個點是根本不需要的,直接打上vis[i][j]=true就是了。除此之外,邊界上的點也要打上true,並且要找個最低的板。那麽需要多次找最低的板,我們自然想到了用堆來刷。最低的板找到了,在呢?例如下圖:
-------------
| | | | |
-------------
| | | |/ \|
-------------
| | |<-|Ls|
-------------
| | | |\ /|
-------------
| | | | |
-------------
假設Ls是最低的板,那麽他可以向4個方向擴展(這裏只有3個)。那麽,我們每擴展到一個格子xx,yy,如果他是合法且沒有被更新過,那麽才能去更新它,因為每個點最多只會被更新1次(因為我們每次都是尋找這些板的最矮的地方,從這個當前最矮的地方擴展到xx,yy。由於我們只是考慮板,而暫時不考慮木桶的內部,所以導致裏面的點也就是後入堆的點影響不到外面的點也就是先入堆的點,那麽我們從堆裏面get出來的x,y這個點是當前木桶的最短一塊木板(所以木桶是有可能變成不規則的),當他更新了點xx,yy以後,接下去的任何一點去更新xx,yy都不是最優的,所以我們只會讓每個點入堆一次,也就是說他只會被更新一次,並且它也只能更新其他格子一次)。那麽,每當這個格子合法且未更新過,那麽要把他打上vis=true,而且要更新new[xx][yy]——
1.if old[xx][yy]<new[x][y] then begin inc(ans,new[x][y]-old[xx][yy]); new[xx][yy]
:=new[x][y];
2.else new[xx][yy]:=old[xx][yy];
對於情況1,就是說如果xx,yy的木板高度<x,y已經更新過(可能有水)的總高度,那麽此時,xx,yy是可以達到new[x][y]的高度的,於是ans+=改變的值;
對於情況2,就是說如果xx,yy的木板高度>=x,y已經更新過(可能有水)的總高度,那麽此時,xx,yy是無論如何不能倒水下去的,所以new的高度等於old的高度的。
那麽,更新過後,我們還要將它put入堆去更新其他的格子。
那麽最後知道len=0也就是所有點都更新過了的時候就break掉,輸出就好了。

技術分享
 1 const fl:array[0..3,0..1] of longint=((-1,0),(0,1),(1,0),(0,-1)); 
 2       maxn=305*305;
 3 var map,dis:array[0..305,0..305] of longint;
 4     vis:array[0..305,0..305] of boolean;
 5     heap:array[0..maxn] of record
 6                              x,y,h:longint;
 7                            end;
 8     n,m,ans,len:longint;
9 procedure init; 10 var i,j:longint; 11 begin 12 readln(m,n); 13 for i:=1 to n do 14 for j:=1 to m do read(map[i][j]); 15 end; 16 procedure put(x,y,h:longint); 17 var son:longint; 18 begin 19 inc(len); heap[len].h:=h; heap[len].x:=x; heap[len].y:=y; son:=len; 20 while son>1 do 21 begin 22 if heap[son>>1].h>heap[son].h then begin 23 heap[maxn]:=heap[son]; 24 heap[son]:=heap[son>>1]; 25 heap[son>>1]:=heap[maxn]; 26 end 27 else break; 28 son:=son>>1; 29 end; 30 end; 31 procedure get; 32 var fa,son:longint; 33 begin 34 heap[1]:=heap[len]; dec(len); fa:=1; 35 while fa<<1<=len do 36 begin 37 if (heap[fa<<1].h<heap[fa<<1+1].h) or (fa<<1+1>len) then son:=fa<<1 38 else son:=fa<<1+1; 39 if heap[fa].h>heap[son].h then begin 40 heap[maxn]:=heap[son]; 41 heap[son]:=heap[fa]; 42 heap[fa]:=heap[maxn]; 43 end 44 else break; 45 fa:=son; 46 end; 47 end; 48 procedure main; 49 var i,x,y,xx,yy:longint; 50 begin 51 for i:=2 to m-1 do begin dis[1][i]:=map[1][i]; put(1,i,map[1][i]); vis[1][i]:=true; end; 52 for i:=2 to m-1 do begin dis[n][i]:=map[n][i]; put(n,i,map[n][i]); vis[n][i]:=true; end; 53 for i:=2 to n-1 do begin dis[i][1]:=map[i][1]; put(i,1,map[i][1]); vis[i][1]:=true; end; 54 for i:=2 to n-1 do begin dis[i][m]:=map[i][m]; put(i,m,map[i][m]); vis[i][m]:=true; end; 55 vis[1][1]:=true; vis[1][m]:=true; vis[n][1]:=true; vis[n][m]:=true; 56 while len>0 do 57 begin 58 x:=heap[1].x; y:=heap[1].y; get; 59 for i:=0 to 3 do 60 begin 61 xx:=x+fl[i][0]; yy:=y+fl[i][1]; 62 if (xx<1) or (xx>n) or (yy<1) or (yy>m) then continue; 63 if vis[xx][yy] then continue; 64 vis[xx][yy]:=true; 65 if dis[x][y]>map[xx][yy] then begin inc(ans,dis[x][y]-map[xx][yy]); dis[xx][yy]:=dis[x][y]; end 66 else dis[xx][yy]:=map[xx][yy]; 67 put(xx,yy,map[xx][yy]); 68 end; 69 end; 70 end; 71 procedure print; 72 begin 73 writeln(ans); 74 end; 75 begin 76 init; 77 main; 78 print; 79 end.
View Code

花神倒果汁