本文主要是介绍LIS(最长上升子序列, 合唱队形),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
最长上升子序列
直接使用动态规划:
这个题目的关键就是在于我们选定一个数,然后利用这个数作为标准和这个数之前的所有数进行比较,如果比前面某一个数要大,那么就需要将这数自己本身的现存的最长长度与比较出来的数的最长加一(这里为什么要加一,因为需要加上前面的长度之外还需要将自己的长度也加上)进行比较,然后取最大。 最后我们还需要在全部所有的数进行一次比较找到最大值,这个最大值就是答案。
这个就是相当于模板 以供后面需要求最长上升子序列的时候使用
代码如下
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int dp[1000000];
int a[1000000];
int main()
{int n;cin>>n;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++){for(int j=0;j<i;j++)//这里值得注意的是,这个是将这个和前面所有的数都进行了一次比较{if(a[i]>a[j])dp[i]=max(dp[i],dp[j]+1);}}int ans=-1;for(int i=1;i<=n;i++){if(ans<dp[i])ans=dp[i];}cout<<ans<<endl;return 0;
}
灵感:对于动态规划来说每一个数组元素都有自己的含义,与上下都是存在关系的
合唱队形
其实这一题也是一个有关最长上升子序列的问题,只不过是先是从1到n求一次上升子序列,然后再是从从n到1求一次上升子序列,然后再在这里面求最优解。
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int dp[1000000];
int dp1[1000000];
int a[1000000];
int sum[100000];
int main()
{int n;cin>>n;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++){for(int j=0;j<i;j++)//这里值得注意的是,这个是将这个和前面所有的数都进行了一次比较{if(a[i]>a[j])dp[i]=max(dp[i],dp[j]+1);}}for(int i=n;i>=1;i--){for(int j=n+1;j>i;j--)//这里需要注意,初始化是从j=n+1开始的,如果不从n+1开始就会少加上自己{if(a[i]>a[j])dp1[i]=max(dp1[i],dp1[j]+1);}}int ans=-1;for(int i=1;i<=n;i++){sum[i]=dp[i]+dp1[i]-1;}for(int i=1;i<=n;i++){if(ans<sum[i])ans=sum[i];}cout<<n-ans<<endl;return 0;
}
这篇关于LIS(最长上升子序列, 合唱队形)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!