当前位置:   article > 正文

2 最长上升子序列及其衍生_最长上升子序列变种

最长上升子序列变种

目录

最长上升子序列模板

1 怪盗基德的滑翔翼

2 登山

3 合唱队形

4 友好城市 (贪心)

5 最长上升子序列和

6 拦截导弹 (贪心)

7 导弹防御系统 (贪心+dfs)

8  最长公共上升子序列 (最长公共子序列+最长上升子序列)

1)朴素版(容易TLE)

2) 分析优化一维

3) 滚动数组优化二维数组变成一维


最长上升子序列模板

信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=1e3+10;
  4. int f[N],a[N];
  5. int main()
  6. {
  7. int n,ans=0;
  8. cin>>n;
  9. for(int i=1;i<=n;i++) cin>>a[i];
  10. for(int i=1;i<=n;i++)
  11. {
  12. f[i]=1;//表示只有自己一个数的时候
  13. for(int j=1;j<i;j++)
  14. if(a[j]<a[i])//假如这个位置上的数比我小
  15. f[i]=max(f[i],f[j]+1);//则进行状态转移
  16. ans=max(ans,f[i]);//更新一下以每个数结尾的最长上升子序列的最大值
  17. }
  18. cout<<ans<<endl;
  19. return 0;
  20. }

1 怪盗基德的滑翔翼

信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

  1. //因为是从一个点可以飞两个方向,故求正向求一次最长上升子序列,逆向也求一次,最后取最大值
  2. #include<bits/stdc++.h>
  3. using namespace std;
  4. const int N=110;
  5. int h[N],f[N];
  6. int main()
  7. {
  8. int t;
  9. cin>>t;
  10. while(t--)
  11. {
  12. int n,ans=0;
  13. cin>>n;
  14. for(int i=1;i<=n;i++) cin>>h[i];
  15. //正向求一次最长上升子序列
  16. for(int i=1;i<=n;i++)
  17. {
  18. f[i]=1;
  19. for(int j=1;j<i;j++)
  20. if(h[j]<h[i])
  21. f[i]=max(f[i],f[j]+1);
  22. ans=max(f[i],ans);//更新最大值
  23. }
  24. //逆向求一次最畅销上升子序列
  25. for(int i=n;i;i--)
  26. {
  27. f[i]=1;
  28. for(int j=n;j>i;j--)
  29. if(h[j]<h[i])
  30. f[i]=max(f[i],f[j]+1);
  31. ans=max(f[i],ans);//更新最大值
  32. }
  33. cout<<ans<<endl;
  34. }
  35. return 0;
  36. }

2 登山

​​​​​​信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=1e3+10;
  4. int h[N],f[N];//f存的是以i结尾的最长上升子序列
  5. int main()
  6. {
  7. int n,ans=0;
  8. cin>>n;
  9. for(int i=1;i<=n;i++) cin>>h[i];
  10. //正向求一次最长上升子序列
  11. for(int i=1;i<=n;i++)
  12. {
  13. f[i]=1;
  14. for(int j=1;j<i;j++)
  15. if(h[j]<h[i])
  16. f[i]=max(f[i],f[j]+1);
  17. }
  18. //逆向求一次最长上升子序列
  19. for(int i=n;i;i--)
  20. {
  21. int flag=f[i];//先把正向的最长上升子序列记录下来
  22. f[i]=1;//在从新求逆向的最长上升子序列
  23. for(int j=n;j>i;j--)
  24. if(h[j]<h[i])
  25. f[i]=max(f[i],f[j]+1);
  26. ans=max(f[i]+flag-1,ans);//更新一下两个和的最大值,因为第i这个数被加了两次1,故结果得减一
  27. }
  28. cout<<ans<<endl;
  29. return 0;
  30. }

3 合唱队形

信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

题意跟登山一模一样,只是结果要的是去掉的人

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=1e3+10;
  4. int h[N],f[N];//f存的是以i结尾的最长上升子序列
  5. int main()
  6. {
  7. int n,ans=0;
  8. cin>>n;
  9. for(int i=1;i<=n;i++) cin>>h[i];
  10. //正向求一次最长上升子序列
  11. for(int i=1;i<=n;i++)
  12. {
  13. f[i]=1;
  14. for(int j=1;j<i;j++)
  15. if(h[j]<h[i])
  16. f[i]=max(f[i],f[j]+1);
  17. }
  18. //逆向求一次最长上升子序列
  19. for(int i=n;i;i--)
  20. {
  21. int flag=f[i];//先把正向的最长上升子序列记录下来
  22. f[i]=1;//在从新求逆向的最长上升子序列
  23. for(int j=n;j>i;j--)
  24. if(h[j]<h[i])
  25. f[i]=max(f[i],f[j]+1);
  26. ans=max(f[i]+flag-1,ans);//更新一下两个和的最大值,因为第i这个数被加了两次1,故结果得减一
  27. }
  28. cout<<n-ans<<endl;//结果要去掉的人
  29. return 0;
  30. }

4 友好城市 (贪心)

信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef pair<int,int> pii;
  4. const int N=5010;
  5. int f[N];
  6. pii he[N];//存两边对应的友好城市
  7. int main()
  8. {
  9. int n,ans=0;
  10. cin>>n;
  11. for(int i=1;i<=n;i++)
  12. {
  13. int a,b;
  14. cin>>a>>b;
  15. he[i]={a,b};
  16. }
  17. sort(he+1,he+n+1);//按北岸的城市排序
  18. //求一下南岸的最长上升子序列
  19. for(int i=1;i<=n;i++)
  20. {
  21. f[i]=1;
  22. for(int j=1;j<i;j++)
  23. if(he[j].second<he[i].second)
  24. f[i]=max(f[i],f[j]+1);
  25. ans=max(ans,f[i]);
  26. }
  27. cout<<ans<<endl;//输出南岸的最长上升子序列,也就是最大不相交数
  28. return 0;
  29. }

5 最长上升子序列

信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef pair<int,int> pii;
  4. const int N=1e3+10;
  5. int f[N],a[N];
  6. int main()
  7. {
  8. int n,ans=0;
  9. cin>>n;
  10. for(int i=1;i<=n;i++) cin>>a[i];
  11. for(int i=1;i<=n;i++)
  12. {
  13. f[i]=a[i];//空的时候,只有自己
  14. for(int j=1;j<i;j++)
  15. if(a[j]<a[i])//假如这个数小于当前数
  16. f[i]=max(f[i],f[j]+a[i]);//进行状态转移
  17. ans=max(ans,f[i]);//更新一下最大值
  18. }
  19. cout<<ans<<endl;
  20. return 0;
  21. }

 

拦截导弹 (贪心)

信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=1e3+10;
  4. int a[N],q[N],f[N];
  5. int main()
  6. {
  7. int n=0;
  8. while(cin>>a[n]) n++;
  9. int ans=0;
  10. //求最长上升子序列
  11. for(int i=0;i<n;i++)
  12. {
  13. f[i]=1;
  14. for(int j=0;j<i;j++)
  15. if(a[j]>=a[i])
  16. f[i]=max(f[i],f[j]+1);
  17. ans=max(f[i],ans);
  18. }
  19. cout<<ans<<endl;
  20. //求覆盖次数,贪心
  21. int cnt=0;
  22. for(int i=0;i<n;i++)
  23. {
  24. int k=0;
  25. while(k<cnt&&q[k]<a[i]) k++;//找现有序列中大于当前数的最小的数
  26. q[k]=a[i];//更新一下当前数
  27. if(k>=cnt) cnt++;//否则开辟新的子序列
  28. }
  29. cout<<cnt;
  30. return 0;
  31. }

 

7 导弹防御系统 (贪心+dfs)

 

187. 导弹防御系统 - AcWing题库

跟拦截导弹的贪心一样,多了dfs

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=60;
  4. int a[N],up[N],down[N];
  5. int ans=0,n;
  6. void dfs(int u,int su,int sd)//u表示当前数,su表示上升子序列的数量,sd表示下降子序列的数量
  7. {
  8. if(su+sd>=ans) return;//加入当前的次数比最小值还大,则return
  9. if(u==n)//否则到了末尾,更新最小值
  10. {
  11. ans=su+sd;
  12. return;
  13. }
  14. //假如加到上升子序列中
  15. int k=0;
  16. while(k<su&&up[k]>=a[u]) k++;
  17. int t=up[k];//把当前数存下来,用来回溯
  18. up[k]=a[u];//更新当前的末尾
  19. if(k<su) dfs(u+1,su,sd);//假如不需要开辟新子序列
  20. else dfs(u+1,su+1,sd);//假如开辟新子序列
  21. up[k]=t;//回溯
  22. //假如加到下降子序列中,做法与上升相同,只不过把大于等于改小于等于
  23. k=0;
  24. while(k<sd&&down[k]<=a[u]) k++;
  25. t=down[k];
  26. down[k]=a[u];
  27. if(k<sd) dfs(u+1,su,sd);
  28. else dfs(u+1,su,sd+1);
  29. down[k]=t;
  30. }
  31. int main()
  32. {
  33. while(cin>>n,n)
  34. {
  35. for(int i=0;i<n;i++) cin>>a[i];
  36. ans=n;
  37. dfs(0,0,0);
  38. cout<<ans<<endl;
  39. }
  40. return 0;
  41. }

 

8  最长公共上升子序列 (最长公共子序列+最长上升子序列)

272. 最长公共上升子序列 - AcWing题库

 

1)朴素版(容易TLE)

 

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=3010;
  4. int a[N],b[N],f[N][N];
  5. int main()
  6. {
  7. int n,ans=0;
  8. scanf("%d",&n);
  9. for(int i=1;i<=n;i++) scanf("%d",&a[i]);
  10. for(int i=1;i<=n;i++) scanf("%d",&b[i]);
  11. for(int i=1;i<=n;i++)
  12. for(int j=1;j<=n;j++)
  13. {
  14. f[i][j]=f[i-1][j];//所有不包含a[i]的最长公共上升子序列
  15. if(a[i]==b[j])//所有包含a[i]的最长公共上升子序列
  16. {
  17. f[i][j]=max(f[i][j],1);//当空的时候是自己,也就是1
  18. for(int k=1;k<j;k++)//求最长公共上升子序列
  19. if(b[k]<b[j])
  20. f[i][j]=max(f[i][j],f[i][k]+1);
  21. }
  22. }
  23. //求最大值,第一个序列的前n个字母,与b的匹配最大
  24. for(int i=1;i<=n;i++) ans=max(ans,f[n][i]);
  25. printf("%d\n",ans);
  26. return 0;
  27. }

 

2) 分析优化一维

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=3010;
  4. int a[N],b[N],f[N][N];
  5. int main()
  6. {
  7. int n;
  8. scanf("%d",&n);
  9. for(int i=1;i<=n;i++) scanf("%d",&a[i]);
  10. for(int i=1;i<=n;i++) scanf("%d",&b[i]);
  11. for(int i=1;i<=n;i++)
  12. {
  13. int maxf=1;//由于在k中重复求前j个最大值,所有用一个maxf记录前j个的最长上升子序列的最大值
  14. for(int j=1;j<=n;j++)
  15. {
  16. f[i][j]=f[i-1][j];//所有不包含a[i]的最长公共上升子序列
  17. if(a[i]==b[j]) f[i][j]=max(f[i][j],maxf);//所有包含a[i]的最长公共上升子序列,更新最大值
  18. if(b[j]<a[i]) maxf=max(maxf,f[i][j]+1);//因为a[i]==b[j]的时候更新最大值,所以可以把b[j]换成a[i],用来与新的b[j]比较
  19. }
  20. }
  21. //最后更新一遍最大值
  22. int ans=0;
  23. for(int i=1;i<=n;i++) ans=max(ans,f[n][i]);
  24. printf("%d\n",ans);
  25. return 0;
  26. }

 

3) 滚动数组优化二维数组变成一维

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=3010;
  4. int a[N],b[N],f[N];
  5. int main()
  6. {
  7. int n,ans=0;
  8. scanf("%d",&n);
  9. for(int i=1;i<=n;i++) scanf("%d",&a[i]);
  10. for(int i=1;i<=n;i++) scanf("%d",&b[i]);
  11. for(int i=1;i<=n;i++)
  12. for(int j=1,maxf=1;j<=n;j++)
  13. {
  14. //因为更新f[i][j]的时候只用到了上一维f[i-1][j]的信息,故可以优化变成一维
  15. if(a[i]==b[j]) f[j]=max(f[j],maxf);
  16. if(b[j]<a[i]) maxf=max(maxf,f[j]+1);
  17. }
  18. //求一遍最大值
  19. for(int i=1;i<=n;i++) ans=max(ans,f[i]);
  20. printf("%d\n",ans);
  21. return 0;
  22. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/415124
推荐阅读
相关标签
  

闽ICP备14008679号