赞
踩
最长上升子序列式dp的一种可以说是最基本的题目
比如:给出一个数列a = {1,3,8,5,6,7,7,7,4,7,4,6,7,8}
显然他的子序列有n^2 个 其中最长的是4,6,7,8
我们给出n^2和nlogn两种做法
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 10010;
int dp[N],a[N],n;
int main(){
memset(dp,0,sizeof(dp));
cin>>n;
for(int i = 1;i <= n;i++){
cin>>a[i];
}
dp[1] = 1; //dp[i] 表示匹配第i的最长的上升子序列
for(int i = 2;i <= n;i++){
dp[i] = 1; //显然对有每一位上升的序列至少为1
for(int j = 1;j < i;j++){
if(a[i] > a[j]){
if(dp[i] < dp[j] + 1){
dp[i] = dp[j] + 1;
}
}
}
}
int ans = 1;
for(int i = 1;i <= n;i++){
if(dp[i] > ans) ans = dp[i];
}
cout<<ans;
return 0;
}
下面是nlogn做法,构造一个辅助数组,随便nlogn做法·和dp没有什么关系
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 10010;
int lis[N],ans,n,a[N]; //lis为辅助数组 记录长度为i的序列中最小的
void HalfDivide(int r,int l,int x);
int main(){
memset(lis,0,sizeof(lis));
cin>>n;
for(int i = 1;i <= n;i++){
cin>>a[i];
}
lis[1] = a[1];
ans = 1;
for(int i = 2;i <= n;i++){
if(lis[ans] < a[i]){
ans++;
lis[ans] = a[i];
}
else HalfDivide(1,ans,i); //1 ans为左右边界,i为下标
//利用二分优化复杂度
}
cout<<ans;
return 0;
}
void HalfDivide(int r,int l,int x){ //如果lis比a[i] 小那么a[i]显然可以接在lis后
int mid = (l + r) / 2; //若不然,就找一个lis s.t. a[i]可以接在它的后面
while(r < l){
if(a[x] < lis[mid]){
r = mid + 1;
}
else{
l = mid;
}
mid = (l + r) >> 1;
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。