HDU-4252 A Famous City(单调栈)

最后更新于2019.1.23

A Famous City

?戳这里可以前往原题

Problem Description

After Mr. B arrived in Warsaw, he was shocked by the skyscrapers and took several photos. But now when he looks at these photos, he finds in surprise that he isn’t able to point out even the number of buildings in it. So he decides to work it out as follows:

  • divide the photo into n vertical pieces from left to right. The buildings in the photo can be treated as rectangles, the lower edge of which is the horizon. One building may span several consecutive pieces, but each piece can only contain one visible building, or no buildings at all.
  • measure the height of each building in that piece.
  • write a program to calculate the minimum number of buildings.
    Mr. B has finished the first two steps, the last comes to you.

Input

Each test case starts with a line containing an integer n (1 <= n <= 100,000). Following this is a line containing n integers - the height of building in each piece respectively. Note that zero height means there are no buildings in this piece at all. All the input numbers will be nonnegative and less than 1,000,000,000.

Output

For each test case, display a single line containing the case number and the minimum possible number of buildings in the photo.

Sample Input

3
1 2 3
3
1 2 1

Sample Output

Case 1: 3
Case 2: 2

题目大意:

将一张照片从左到右分为N个垂直部分。照片中的建筑物可以被视为矩形,一栋建筑可以跨越几个连续的部分,但每个部分只能包含一个可见的建筑,或者根本没有建筑。根据每个部分的高度,求出照片中最少建筑物数量

解题思路:

考虑最优情况,及每一种高度就只有一个建筑物,则最少建筑物数量及等于高度的种数。
根据高的建筑物覆盖低的建筑物原则,也就是说,如果两个矩形之间的所有建筑物的高度都大于等于这两个矩形,且这两个矩形高度相等,我们就可以把这两个矩形视为同一个建筑物。反过来,如果这两个矩形之间的建筑物中出现了更低的矩形,那么这两个就一定不能连成一个建筑物。

推广上面的结论:
1、如果所有的矩形高度维持从小到大的顺序,则最少建筑物数量及等于高度的种数。
2、如果出现了比上一个矩形更低的矩形,则上一个矩形所对应的建筑物不能再与后面的建筑物连成一个,则我们可以结算掉前面已经出现的矩形中,高于新加入的矩形的个数。

也就是说,我们需要把不断递增的序列保存下来,然后维护这个序列保持严格递增,即可得到答案,即维护一个单调栈

下面是AC代码

#include <bits/stdc++.h>

using namespace std;

stack<int> st;//栈

int main()
{
    ios::sync_with_stdio(false);

    int n;
    int cases=1;
    int answer;
    while (cin>>n)
    {
        answer=0;
        int temp;
        //由于我们最后计算个数时必然会把栈内的数据全部弹出,则不需要清空栈
        while (n--)
        {
            cin>>temp;
            if (st.empty())//如果栈内为空,则直接推入栈
            {
                st.push(temp);
                continue;
            }
     		//如果出现比栈内所有值都高的一个值,则可以直接入栈(由于我们维护的是单调栈,所以栈顶的元素一定是最大的,所以只需要比较栈顶的元素)
            if (temp>st.top())
            {
                st.push(temp);
            }
            else if (temp<st.top())//反之则把大于新的数据的值都从栈中弹出
            {
                while ((!st.empty()) && (st.top()>temp))
                {
                    answer++;
                    st.pop();
                }
                if (st.empty())//如果已经弹空
                {
                    st.push(temp);
                    continue;
                }
                if (st.top()!=temp)//如果将要入栈的值与上一个值发生重复,则不需要压入栈,这里判断的是不重复的情况
                {
                    st.push(temp);
                }
            }
        }
        while(!st.empty())//结算栈中剩下的部分
        {
            if(st.top())//这里是此题的一个坑,因为可能出现高度为0的情况,而0是没有建筑的
            {
                answer++;
            }
            st.pop();
        }
        cout<<"Case "<<cases<<": "<<answer<<endl;
        cases++;
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值