题目描述
Whenever it rains, Farmer John's field always ends up flooding. However, since the field isn't perfectly level, it fills up with water in a non-uniform fashion, leaving a number of "islands" separated by expanses of water.
FJ's field is described as a one-dimensional landscape specified by N (1 <= N <= 100,000) consecutive height values H(1)...H(n). Assuming that the landscape is surrounded by tall fences of effectively infinite height, consider what happens during a rainstorm: the lowest regions are covered by water first, giving a number of disjoint "islands", which eventually will all be covered up as the water continues to rise. The instant the water level become equal to the height of a piece of land, that piece of land is considered to be underwater.
An example is shown above: on the left, we have added just over 1 unit of water, which leaves 4 islands (the maximum we will ever see). Later on, after adding a total of 7 units of water, we reach the figure on the right with only two islands exposed. Please compute the maximum number of islands we will ever see at a single point in time during the storm, as the water rises all the way to the point where the entire field is underwater.
每当下雨的时候,农夫约翰的田地总是被洪水淹没。然而,由于场地并不是完全平坦的,它以一种不均匀的方式充满了水,留下了一些被大片的水分隔开的“岛屿”。FJ 的场被描述为由 N (1 < = N < = 100,000)连续高度值 H (1) ... H (n)指定的一维景观。假设景观被实际上无限高的高栅栏所包围,想象一下在暴风雨中会发生什么: 最低的区域首先被水覆盖,形成一些不相连的“岛屿”,随着水位继续上升,这些岛屿最终都会被覆盖。当水位等于一块陆地的高度时,这块陆地就被认为是水下的。
上面的例子显示: 在左边,我们已经添加了刚刚超过1个单位的水,这留下了4个岛屿(最大的,我们将永远看到)。后来,在总共添加了7个单位的水,我们达到了右边的数字,只有两个岛屿暴露。请计算一下在暴风雨期间,我们在某一时刻所能看到的最大岛屿数量,因为水位一直上升到整个田野都被水淹没的地方。
输入
* Line 1: The integer N.
* Lines 2..1+N: Line i+1 contains the height H(i). (1 <= H(i) <= 1,000,000,000)
*第一行:一个整数N
* 第2行. . 1 + N: 第 i + 1行包含高度 H (i) . (1 < = H (i) < = 1,000,000,000)
输出
* Line 1: A single integer giving the maximum number of islands that appear at any one point in time over the course of the rainstorm.
* 第1行: 一个整数,表示在暴雨过程中任何一个时间点出现的最多岛屿数目。
样例输入
8
3
5
2
3
1
4
2
3
样例输出
4
提示
INPUT DETAILS:
The sample input matches the figure above.
输入细节: 示例输入与上图匹配。
分析
从样例看出,田是否被淹没,我们只需要关心他的高度是否大于等于田的高度(题中说一旦水位等于一块田地的高度,那块田地就被认为位于水下;即使题中未说明,我们也可以通过添加一点点水来淹没它)。
所以,我们可以通过模拟淹没的方法来解这道题。
而模拟的次数等于田不同高度的数量,因为高度相同的田会在同一时间被淹没。
例如样例中先后灌入高度为 1,2,3,4,5 的水,直至全部被淹没。
而在淹没的过程中,我们会遇到如下几种情况:
1.田不在最左端,也不在最右端,且中间的田比相邻两侧的高,即孤岛。如果此时该田被淹没,那么岛屿的数量就会减 1;
2.田不在最左端,也不在最右端,且中间的田比相邻两侧的矮,即洼地。
如果此时该田被淹没,那么左右两边高于它的田,会形成两个岛,而之前这三块田连在一起只有一个岛屿,说明岛屿的数量会加 1;
3.在岛屿的最左端,且其右边的田比其矮,还是孤岛。如果该田此时被淹没,这座孤岛就会消失,说明岛屿的数量会减 1;
4.在岛屿的最右端,且其左边的田比其矮,依然孤岛。如果该田此时被淹没,这座孤岛就会消失,说明岛屿的数量会减 1;
5.不在最左端,也不在最右端,中间的田比一侧高,比一侧矮,则淹没它对岛屿数量没有贡献,并不会增加或者减少岛屿数量。
6.在岛屿的最左端,且其右边的田比其高。则该田被淹没没有影响;
7.在岛屿的最右端,且其左边的田比其高,则该田被淹没没有影响;
8.与之相连的田与之高度相同,由于会同时被淹没,所以这些相连的、高度相同的田可以看作是同一块田,在读入的时候可以直接将相连的且高度相同的田合并(合并的充分性)。如果我们在淹没两个相连的高度相同的岛时,但看其中一个我们无法判断淹没它对岛屿的贡献,即无法明确知道淹没该田后岛屿数是增加,减少,还是不变。
从上面这些情况可以看出,当两块相同高度的田连在一起时,无法通过一块田判断淹没该田对总岛数的贡献。
所以,读入数据时我们先对相邻的高度相同的田进行去重。
然后将田由低到高进行升序排序,并由低到高模拟被淹没的情形。
注意:由于同一高度是在同一时间被淹没的,所以更新岛的数量的时候,需要等相同高度的所有岛都淹没完才能更新。
代码
想必前面看晕了吧,没关系,下面注释帮你理解
#include <iostream>
#include <cstring>
#include <algorithm>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 100001;
int n;
int h[N]; // 记录田的高度
PII q[N]; // 记录该高度的田的原始位置
int main()
{
scanf("%d", &n);
for(int i = 0; i < n; i++) scanf("%d", &h[i]);
n = unique(h, h + n) - h; // 将相邻的高度相同的田去重
for(int i = 0; i < n; i++) q[i] = {h[i], i}; // 记录田原始的相对位置
sort(q, q + n); // 将田升序排序,方便从低到高模拟淹没
int current = 1; // 记录当前的岛屿数量,最开始所有田都是同一个岛屿
int res = 1; // 记录最大的岛屿数量
int pre = -1; // 记录前一块淹没的田的数量
for(int i = 0; i < n; i++)
{
int high = q[i].x; // 当年淹没的高度
int j = q[i].y; // 当前淹没的田的原始位置
if(high != pre) // 如果前一个高度的田已经全部淹没完了,则更新当前的岛屿数
{
pre = high; // 表示开始淹没新的高度的田了
res = max(res, current);
}
if(j - 1 >= 0 && j + 1 < n)
{
if(high > h[j - 1] && high > h[j + 1]) current--; // 如果中间的田比两侧的高,即孤岛
else if(high < h[j - 1] && high < h[j + 1]) current++; // 如果中间的田比两侧的低,即洼地
}
if(j == 0 && h[j] > h[j + 1]) current--;
else if(j + 1 == n && h[j] > h[j - 1]) current--;
}
res = max(res, current);
printf("%d\n", res);
}
给个赞和关注吧