生活随笔
收集整理的這篇文章主要介紹了
土地积水
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
http://www.byvoid.com/blog/poi-1999-wod/zh-hans/
有一塊矩形土地被劃分成 N×M 個正方形小塊,每塊是一平方米。這些小塊高低不平,每一小塊地都有自己的高度H(i, j)米。水可以由任意一塊地流向周圍四個方向的四塊地中,但不能直接流入對角相連的小塊中。一場大雨后,許多低洼地方都積存了不少降水,求出它最多能積存多少立方米的降水么?
根據木桶原理,水位的高低取決于最低的邊界。我們可以從最低的邊界入手,向內灌水,使水面于邊界齊平。如果灌到了新的邊界,而且不低于最低的邊界,則這個點一定是不能被灌水的。
可以想象成一個深度搜索的過程,我們從最低邊界開始灌水,遇到比最低邊界低的,它的水平面頂多就是最低邊界,直到遇到一個邊界比最低邊界高的,將高邊界放入優先隊列中。
每次取邊界最小值向內灌水,于是可以用一個最小堆來維護高度。
算法流程如下:
把所有的邊界上的點加入堆,且標記為已使用過。取出高度最小的點(x,y),枚舉與(x,y)相鄰的未使用過的點(x’,y’),從(x’,y’)開始Floodfill,邊界高度h=(x,y)的高度。重復第二步,直到堆為空。
標記(x,y)為已使用過。如果(x,y)的高度>=h,則該點不能積水,加入堆并返回。否則(x,y)的點的積水量為h-(x,y)的高度。枚舉與(x,y)相鄰的未使用過的點(x’,y’),Floodfill(x’,y’)。
/* * Problem: POI1999 wod* Author: Guo Jiabao* Time: 2008.12.16 21:44:50* State: Solved
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>using namespace std;const int MAX=101;
const int dx[4]={0,0,-1,1},dy[4]={1,-1,0,0};struct point
{int x,y;
};int N,M,All;
int Alt[MAX][MAX];
bool vid[MAX][MAX];
int heap_size;
point Heap[MAX*MAX];void heap_ins(int x,int y)
{int i;for (i=++heap_size;Alt[x][y]<Alt[Heap[i/2].x][Heap[i/2].y];i=i/2)Heap[i]=Heap[i/2];Heap[i].x=x; Heap[i].y=y;
}point heap_delmin()
{point R=Heap[1],M=Heap[heap_size--];int i,c;for (i=1;i*2<=heap_size;i=c){c=i*2;if (c!=heap_size && Alt[Heap[c+1].x][Heap[c+1].y]<Alt[Heap[c].x][Heap[c].y])c++;if (Alt[M.x][M.y] > Alt[Heap[c].x][Heap[c].y])Heap[i]=Heap[c];elsebreak;}Heap[i]=M;return R;
}void init()
{freopen("wod.in","r",stdin);freopen("wod.out","w",stdout);scanf("%d%d",&N,&M);for (int i=1;i<=N;i++)for (int j=1;j<=M;j++)scanf("%d",&Alt[i][j]);Alt[0][0]=-0x7FFFFFFF;Heap[heap_size=0].x=Heap[0].y=0;
}inline bool inrange(point A)
{return A.x>=1 && A.x<=N && A.y>=1 && A.y<=M;
}void floodfill(point A,int h)
{point B;vid[A.x][A.y]=true;if (Alt[A.x][A.y]>=h)heap_ins(A.x,A.y);else{All+=h-Alt[A.x][A.y];for (int i=0;i<4;i++){B.x=A.x+dx[i]; B.y=A.y+dy[i];if (inrange(B) && !vid[B.x][B.y])floodfill(B,h);}}
}void solve()
{int i,j;point A,B;for (i=1;i<=N;i++){heap_ins(i,1);heap_ins(i,M);vid[i][1]=vid[i][M]=true;}for (i=2;i<=M-1;i++){heap_ins(1,i);heap_ins(N,i);vid[1][i]=vid[N][i]=true;}while (heap_size){A=heap_delmin();for (i=0;i<4;i++){B.x=A.x+dx[i]; B.y=A.y+dy[i];if (inrange(B) && !vid[B.x][B.y])floodfill(B,Alt[A.x][A.y]);}}
}int main()
{init();solve();printf("%d",All);return 0;
}
還有一種方法,還是比較精巧的。
先考慮我們的土地是一維的,首先定義兩個數字,left,right
left[i]記錄的是從0~i-1最高的高度,right[i]記錄的是從n~i+1最高的高度
那么i的水平面高度是,min(left[i], right[i]) - h[i]
https://github.com/codingtest/interview/blob/master/code2.cpp
#include <stdio.h>
#include <vector>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>using namespace std;//有一塊矩形土地被劃分成 N×M 個正方形小塊,每塊是一平方米。這些小塊高低不平,
//每一小塊地都有自己的高度H(i, j)米。水可以由任意一塊地流向周圍四個方向的四塊地中,
//但不能直接流入對角相連的小塊中。一場大雨后,許多低洼地方都積存了不少降水,求出它最多能積存多少立方米的降水么?
int trap(int* a, int n)
{if ( a == NULL || n == 0 )return 0;int* left = new int[n];if ( left == NULL )return 0;int* right = new int[n];if ( right == NULL )return 0;int maxL = 0;for ( int i = 0 ; i < n-1; i++ ){left[i] = maxL;maxL = max(maxL, a[i]);}int maxR = 0;for ( int i = n-1; i >= 0; i-- ){right[i] = maxR;maxR = max(maxR, a[i]);}int res = 0;for ( int i = 0 ; i < n-1 ;i++){int v = min(left[i], right[i]) - a[i];if ( v > 0 )res += v;}delete[] left;delete[] right;return res;
}
總結
以上是生活随笔為你收集整理的土地积水的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。