土地积水
来源:互联网 发布:阿里云学生认证账号 编辑:程序博客网 时间:2024/04/28 03:36
土地积水
分类: 算法2012-10-29 10:40 230人阅读 评论(2) 收藏 举报
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];
- else
- break;
- }
- 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;
- }
- 土地积水
- 土地积水
- 积水问题
- 积木积水
- 点点滴滴,积水成海
- 下雨积水问题
- GDUT 积木积水(栈)
- gdutProblem E: 积木积水
- 洛谷 P1318 积水面积
- P1318 积水面积
- luogu P1318 积水面积
- 土地测量
- 土地制度
- 分土地
- 土地测量
- 土地测量
- 土地购买
- 土地分类
- Android基础知识之Manifest文件的组织结构
- Android基础知识之Manifest文件中的用户权限元素
- Android基础知识之API等级介绍
- android开发前奏曲之开发工具ADT
- LVL类及接口使用介绍(License Verification Library )
- 土地积水
- Android基础知识之String类使用详解
- Android呼叫管理服务之会话发起协议(SIP)API
- Android 设备管理API概览(Device Administration API)
- 如何在Google Play商店发布多个版本apk
- 用户体验
- 使用Ant编译和构建项目指南
- 一种解决新版本API完全兼容老版本API的方法
- 开发前奏曲之添加Android SDK平台工具