首先对题目进行分解。
找峰值The Best Peak Shape,可以理解成一个峰值点,或者也可以理解成截断点,和两条单调的子序列。
首先很容易就能想到,从前往后求上升A[i],从后往前上升的B[i],再对所有求得的值进行遍历,可以找到满足:A[i]+B[i]最大的情况下,|A[i]-B[i]|最小。
那么我们先对子序列进行分析。
我们可以看到这是一个LIS问题(Longest Increasing Subsequence),也就是说找到最长上升子序列.
那么在动态规划的学习以前,我们尝试用已有的知识尝试对这个问题进行解决。
方法一 有向图可以使用BST或者DST进行搜索
我们发现寻找这个最长子序列的过程可以理解成一个有向图里的搜索问题。
-INF->1->3->4->6->2->5->+INF
1->2 1->5 1->6
3->6 3->4
相当于是求从原点到最终点的最长路径
那么结合我们已有的知识,我们可以使用DFS或者BFS进行搜索。
但在这里会超时过不了测试点
复杂度分析比较困难,在最坏情况下,比如在一个递增的序列中求最长子序列,他的复杂度会达到2^n
#include<iostream>
#include<stack>
using namespace std;
int n;
int number[10001];//the data set by the user
int a[10001];//memerize the length from the front
int b[10001];//memerize the length from the back
stack<int> s;
//search from front to back
void dfs_front(int i)
{
//the search rearch to the end
if (i == n)
{
return;
}
//update
if (s.size()>a[i])
a[i] = s.size();
//add a[i]
if (s.empty() || number[i]>s.top())
{
s.push(number[i]);
//update
if (s.size()>a[i])
a[i] = s.size();//the LIS before number[i]
dfs_front(i + 1);//search further
s.pop();
}
dfs_front(i + 1);//search further
}
//search from back to front
void dfs_back(int i)
{
//the search rearch to the end
if (i == -1)
{
return;
}
if (s.size()>b[i])
b[i] = s.size();
//add b[i]
if (s.empty() || number[i]>s.top())
{
s.push(number[i]);
if (s.size()>b[i])
b[i] = s.size();
dfs_back(i - 1);//search further
s.pop();
}
dfs_back(i - 1);//search further
}
void handle_result()
{
int best = 0;
int num;
int sub;
for (int i = 0; i < n; i++)
{
if (1 == a[i] || 1 == b[i]) //if don't have peak
continue;
if (a[i] + b[i] > best)//update the best
{
best = a[i] + b[i];
num = i;
sub = abs(a[i] - b[i]);
}
else if (a[i] + b[i] == best)//update the best for have a better shape
{
if ( abs(a[i] - b[i]) < sub)
{
num = i;
sub = abs(a[i] - b[i]);
}
}
}
if (0 == best)
//don't have peak shape
cout << "No peak shape" << endl;
else
//the best has count the peak twice
cout << best - 1 << " " << num + 1 << " " << number[num] << endl;
}
int main()
{
cin >> n;
int i;
for (i = 0; i < n; i++)
{
cin >> number[i];//inilize the number
}
dfs_front(0);//search from front
dfs_back(n - 1);//search from back
handle_result();//handle the result after the two search
system("pause");
return 0;
}
方法二 下面两种用动态规划
我们开始考虑这个问题有没有更好的处理方法。我们尝试对这个问题进行分解。
对于一个新加入的数m,他能构成的子序列只有两种情况:一种是由只它自己构成也就是长度为1,另一种是它跟在其他子序列