最长递增子序列(longest increasing subsequence,LIS)的长度,计算LIS最常规的解法是动态规划法(时间复杂度为O(n^2) ),其思想为:
设max_len[i](初始值可全部设为1)表示arr中以arr[i]为末元素的最长递增子序列的长度,则有如下的递推思路:
在求以arr[i]为末元素的最长递增子序列时,在序号i前面找到所有满足能使arr[i]作为末元素的递增子序列要求的元素arr[j],即:
j<i,且arr[i]>arr[j]且(max_len[j]+1)>max_len[i];如果满足,则使max_len[i]=max_len[j]+1.最后在数组max_len[N]中找出最大值即为最长递增子序列的长度。
int LIS(int *arr, const int N)
{
int* max_len = new int[N];
max_len[0] = 1;
int i;
for(i=1; i<N; i++)
{
max_len[i] = 1;
for(int j=0; j<i; j++)
{
if(arr[i] > arr[j]) //如果求最长递减,则改为<
{
max_len[i] =max(max_len[j]+1,max_len[i]);
}
}
int result = 0;
for(i=0; i<N; i++)
result =max(max_len[i],result);
delete[] max_len;
return result;
}
}
1、题目描述
Redraiment是走梅花桩的高手。Redraiment总是起点不限,从前到后,往高的桩子走,但走的步数最多,不知道为什么?你能替Redraiment研究他最多走的步数吗?
样例输入
6
2 5 1 5 4 5
样例输出
3
int LIS(int *arr, const int N)
{
int* max_len = new int[N];
max_len[0] = 1;
int i;
for(i=1; i<N; i++)
{
max_len[i] = 1;
for(int j=0; j<i; j++)
{
if(arr[i] > arr[j])
{
max_len[i] =max(max_len[j]+1,max_len[i]);
}
}
int result = 0;
for(i=0; i<N; i++)
result =max(max_len[i],result);
delete[] max_len;
return result;
}
}
2、题目描述
计算最少出列多少位同学,使得剩下的同学排成合唱队形
说明:
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足存在i(1<=i<=K)使得Ti<T2<......<Ti-1<Ti>Ti+1>......>TK。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
输入例子:
8
186 186 150 200 160 130 197 200
输出例子:
4
思路:两遍最长递增子序列,第一遍从左往右,第二遍从右往左,然后把两遍动态规划的结果相加,取最大的那个,比如比如{86 186 150 200 160 130 197 200},第一遍dp的结果是 1 1 1 2 2 1 3 4,第二遍dp的结果为3 3 2 3 2 1 1 1,那么相加最大是5,所以需要出列的同学个数就是8-5+1=4(为什么加1,中间的数多算了一次)。代码如下:
int my_solve(int *arr, const int N)
{
int* max_len1 = new int[N];
int* max_len2 = new int[N];
//第一遍遍历
max_len1[0] = 1;
int i;
for(i=1; i<N; i++)
{
max_len1[i] = 1;
for(int j=0; j<i; j++)
{
if((arr[i] > arr[j]))
{
max_len1[i] =max(max_len1[j]+1,max_len1[i]);
}
}
}
//第二遍遍历
reverse(arr,arr+N);//先将arr进行翻转
max_len2[0] = 1;
for(i=1; i<N; i++)
{
max_len2[i] = 1;
for(int j=0; j<i; j++)
{
if((arr[i] > arr[j]))
{
max_len2[i] =max(max_len2[j]+1,max_len2[i]);
}
}
}
reverse(max_len2,max_len2+N);//将max_len进行翻转
int result = 0;
for(i=0; i<N; i++)
result =max(max_len1[i]+max_len2[i],result);
delete[] max_len1;
delete[] max_len2;
return result;
}
主函数代码:
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<vector>
#include<assert.h>
using namespace std;
#define max(a,b) ((a)>(b) ? (a):(b))
int LIS(int *arr, int N) ;
int my_solve(int *arr, const int N);
int main()
{
int N;
while(cin>>N)//输入数组的大小
{
int *data=new int[N];
for(int i=0;i<N;i++)
cin>>data[i];
cout<<"最长递增子序列的长度为:"<<LIS(data,N)<<endl;
cout<<"最少需要"<<N-my_solve(data,N)+1<<"位同学出列"<<endl;
}
return 0;
}