前言:
最近感觉算法是一个很重要的东西,于是又把以前的OJ捡起来做做了,看到一题叫做积水量的题目,通过率是100%,虽然说是没有什么挑战,不过很久没写OJ了,让自己进入状态也不错的。
描述:
凹凸不平的地面每当下雨的时候总会积水。假设地面是一维的,每一块宽度都为1,高度是非负整数,那么可以用一个数组来表达一块地面。例如[0,1,0,2,1,0,1,3,2,1,2,1]可以用来表示下图地面:
输入
第一行是一个整数m,表示有m组试样例,不超过100。接下来m块,每块第一行是一个正整数n,表示地面总宽度(数组长度),不超过20000。
接下来一行是n个整数,用空格隔开,表示地面高度。
输出
对于每组输入,输出一个整数表示积水量。
源代码示例:
#include <stdio.h> #define MAX 20000 #define HAD_WALL 1 #define NO_WALL 0 int calWater(int w[], int n) { int i, j; int max, flag; int part, sum; // 找出w[]中最大的一个数 for (i = 0, max = 0; i < n; ++i) { if(w[i] >= max) max = w[i]; } // 从下往上依次遍历 for (i = 0, sum = 0; i < max; ++i) { // 对每一趟进行遍历 for(j = 0, flag = NO_WALL, part = 0; j < n; ++j) { if(w[j] > i && !flag) // 没有墙,并且遇到了一面墙,设置flag标志为IS_WALL { flag = HAD_WALL; } if(w[j] <= i && flag) // 有墙,并且此点不是墙,这一小段的缓冲距离part+1 { ++part; } // 有墙,并且遇到了结束墙,就这个墙和前一个墙之间的距离叠加,缓冲距离归零 if(w[j] > i && flag) { sum += part; part=0; } } part=0; // 遍历完一趟,缓冲距离清零 } return sum; } int main( ) { int m; int n, i; int floor[MAX]; scanf("%d", &m); while(m--) { scanf("%d", &n); for (i = 0; i < n; ++i) { scanf("%d", &floor[i]); } // 计算积水量 int s = calWater(floor, n); printf("%d ", s); } return 0; }
当下过雨后,地面就会积水,上图中蓝色的区域就是积水区域。现在给你一个数组表示地面,求下过雨后这块地面有多少积水量(假设不蒸发、不渗透)。
解析:
当同学们看到这题目的时候,可能会被题目中的图所迷惑,以为应该按列来计算。我也是,当然这只是第一感觉,后来一想,按列来算不可能,这样还必须记录之前那个有障碍物的地方,还有它的高度,很麻烦。
其实我们的想法很简单,首先我们要明确这题应该从行上来考虑,而且还是要从下往上来计算,因为障碍物是只要上面有,下面的一格必定会有障碍物。还有就是我们要知道只有在障碍物和障碍物之间才可能会有积水产生,那么,我们就要去确定障碍物的边界问题。
我们可以在第一次遇到障碍物的时候,设置一个标记参数为已经有了障碍物,当下次我们再一次遇到障碍物的时候,那么这两个相邻的障碍物之间的部分正是我们想要的。最后再把它们累加起来,就大功告成了。。。
下面贡献出我的代码,当然我知道还有大牛能写出更牛的代码,求轻喷。。。
原题地址: