每一个数之前的上升序列个数
dp[i]:以ai为末尾的最长上升子序列的长度
以ai结尾的上升子序列是:
只包含ai的子序列
在满足j<i且aj<ai的以aj为结尾的上升子序列末尾,追加上ai后得到的子序列(时间为O(n^2))
#include <bits/stdc++.h>
using namespace std;
int dp[1001];
int n,a[1001];
int main(){
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
int res=0;
for(int i=0;i<n;i++){
dp[i]=1;
for(int j=0;j<i;j++)
if(a[j]<a[i])
dp[i]=max(dp[i],dp[j]+1);//因为本身就是1个了
res=max(res,dp[i]);
}
printf("%d\n",res);
return 0;
}
用DP针对相同长度情况下最小末尾元素进行求解
最开始全部dp的值初始化为INF。然后由前到后逐个考虑数列的元素,对于每个aj,如果i=0或者dp[i-1]<aj的话,就用dp[i]=min(dp[i],aj)进行更新,最终找到是的dp[i]<INF的最大的i+1就是结果了。利用二分搜索(时间O(nlogn))
#include <bits/stdc++.h>
using namespace std;
int dp[1001];
int n,a[1001];
int INF=1000000;
int main(){
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
fill(dp,dp+n,INF);
for(int i=0;i<n;i++)
*lower_bound(dp,dp+n,a[i])=a[i];
printf("%d\n",lower_bound(dp,dp+n,INF)-dp);
return 0;
}
知识点补充
- lower_bound( )和upper_bound( )都是利用二分查找的方法在一个排好序的数组中进行查找的。
- 在从小到大的排序数组中,
- lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
- upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
- 在从大到小的排序数组中,重载lower_bound()和upper_bound()
- lower_bound( begin,end,num,greater<type>() ):从数组的begin位置到end-1位置二分查找第一个小于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
- upper_bound( begin,end,num,greater<type>() ):从数组的begin位置到end-1位置二分查找第一个小于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
FatMouse's Speed
//#include <bits/stdc++.h>
using namespace std;
int dp[1001],rem[1001];
int a[1001];
int INF=1000000;
typedef struct Mouse{
int weight;//重量
int speed;//速度
int num;//编号
}mice;
mice s[10001];
bool cmp(mice x,mice y){
if(x.weight==y.weight)
return x.speed<y.speed;
else
return x.weight>y.weight;
}
int main(){
int n,m,maxn,i,j,k,t,mark;
for(i=1;i<10001;i++)
rem[i]=i;//每只记录的老鼠都是自己
k=1;
while(scanf("%d%d",&s[k].weight,&s[k].speed)!=EOF){
s[k].num=k;
k++;
}
sort(s+1,s+k,cmp);//排序啦
for(i=1,m=0;i<k;i++){
maxn=0;//maxn表示最大的子序列长度 即 找到符合条件最多的老鼠数量
for(j=1;j<i;j++){
if(s[i].weight<s[j].weight&&s[j].speed<s[i].speed){
if(maxn<dp[j]){//此时数量大于记录数量
maxn=dp[j];//把数量赋给maxn
mark=s[j].num;//几下这只老鼠的编号
}
}
if(maxn)//如果最大数量存在;
rem[s[i].num]=mark;//将用于比较的老鼠编号和记录的老鼠编号对应记下来
dp[i]=maxn+1;//每次要更新,如果maxn为零,加上1就是包括自己啦
if(m<dp[i]){//m是记录符合条件的最大老鼠数量
m=dp[i];
t=s[i].num;//t是记录最后一只符合条件老鼠的编号,方便输出
//因为i是后面的,j是i前面的呀
}
}
}
if(m==1)//当m等于1是即没有符合条件的其他老鼠,那随便哪只都可以啦
cout<<1<<endl<<1<<endl;
else{
cout<<m<<endl;
while(rem[t]!=t){//如果此时老鼠编号对应的老鼠不是自己
cout<<t<<endl;
t=rem[t];
}
cout<<t<<endl;
}
return 0;
}
转载于:https://www.jianshu.com/p/6c97785186ec