高山算法?其实是贪心啦!

来源:互联网 发布:长得帅的女生知乎 编辑:程序博客网 时间:2024/04/30 04:04

近来往往看到过一种类型的贪心的题,就是那种不明所以却有感觉好神奇啊的那种题。
直接上例题。

AtCoder 064 D

那么就来想一想这道题的做法,一开始以为是道栈的题,但发现栈底无法处理,那么就双向队列吧,但发现中间无法插入,那么就splay的合并分裂吧,那么最小字典序呢?拜托,这是beginner的难度。。。
思考了一会儿,
对于一串括号,我只需要正着搜索,反着搜索不就行了吗?
每次记录右减左与左减右的max再printf就可以了吧。。。
naive code

#include<iostream>#include<cstdio>#include<cstring>#include<stack>#include<algorithm>using namespace std;string st;stack<int> sa;int a[1000],sum[1000],len=1,cnt=0,rd=0,ld=0,l=0,r=0;int n,flag=-1;int main(){    cin>>n>>st;    for(register int i=0;i<n;i++){        if(st[i]=='(')a[i]=1;        else a[i]=0;    }    for(register int i=0;i<n;++i){        if(a[i]==1)l++;        else r++;        rd=max(rd,r-l);    }    l=r=0;    for(register int i=n-1;i>=0;--i){        if(a[i]==1)l++;        else r++;        ld=max(ld,l-r);    }    for(register int i=1;i<=rd;++i)cout<<'(';    for(register int i=0;i<n;++i)cout<<st[i];    for(register int i=1;i<=ld;++i)cout<<')';    return 0;}

由此引入我所谓的高山算法。
为什么叫做高山算法?因为每走一步都要测量一下,当前维护信息的值,而最后所需的值并不一定是末尾所处理的值,而是过程中某一处的特值,一般是最大最小值。
Q:为什么叫做高山算法?
A:这是模拟爬山的测量的一个过程,更类似于扫描线,而已经有爬山这个算法了,所以就叫高山算法吧。
Q;这个算法有什么用?
A:其实并没有什么意思,只是提出这样一个类扫描线的贪心算法,有助于理解O(n)复杂度类寻找简单类型的查询问题。
Q:还有什么例题?(该不会是你一时兴起决定的吧?)
A:下方(是的)。

例一 Maximum Sum Sequence

好吧,确实是道naive的题,秒了。代码Leaderboard中有。

例二 Maximum Sum Sequence II

这道题就有意思了吧,还是高山算法,如何做?
其实加个预处理就好了。。。
代码还是见Leaderboard。

LAST ONE 例三

Largest Rectangle in Histogram

之所以不发链接,是因为这道题蛮经典的,到处到可测,例如SPOJ。
这是体现出高山算法在贪心算法中都有无与伦比的“脑洞值”的优秀题目,所以这道题值得一做。

问题描述:给定一个长度为n的直方图,我们可以在直方图高低不同的长方形之间画一个更大的长方形,求该长方形的最大面积。例如,给定下述直方图,

这里写图片描述

我们可以以高度5宽度2画一个更大的长方形,如下图,该长方形即是面积最大的长方形。该问题是难度比较大的问题,但是很出名,经常作为面试题出现。用高山算法可以做到O(n)的复杂度,非常巧妙,并从二维三维角度对问题进行了扩展。

这里写图片描述
仔细思考吧,毕竟高山算法其实挺简单的。

高山==单调队列/单调栈?

不是这样,单调队列需要维护一整个队列的单调性,单调栈同理,而高山算法不改变遍历时的处理顺序,不用额外的数据结构存储,是一个面向答案编写程序的算法。

总结

没什么好说的,这样一个奇妙的算法究竟能够延展到什么程度?静待吧。

原创粉丝点击