日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

土地积水

發布時間:2024/9/30 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 土地积水 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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)的高度。
  • 重復第二步,直到堆為空。
    • Floodfill(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; }

    總結

    以上是生活随笔為你收集整理的土地积水的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。