2012 US OPEN BRONZE 3.Islands

题目描述

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);
}

给个赞和关注吧

  • 46
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值