前言
这次是的代码自己思考的占了90%,有进步的一匹,感觉自己又可以了,现在已经基本掌握了动态规划的基本思想,加油!!!
一、题目
二、求LIS方法
1.利用最长公共子序列LCS求LIS
例如要求A={5,6,7,4,2,8,3}的LIS,对A排序str1={2,3,4,5,6,7,8},所以要求A的LIS,其实就是求A和str1的最长公共子序列
求LCS方法就不再写一遍了,之前写过
LCS求法
2.用DP写LIS
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int dp[1005];
int a[1005];
//思路:
/*
dp[i]存前i个数中的最大递增子序列(LIS)长度;
首先初始化dp[0]=1;一个数的时候 LIS长度为1;
循环边输入边遍历,想找到一个LIS,可以从头看,
满足这个序列的第一层条件是要小于a[i],
然后定义的dp已经存储了最大长度,所以第二层条件就是找到最大的dp值
让其加一,得到的结果就是dp[i]的值
这里我只输出了数组a中以每个数为结尾的LIS的长度,
再对dp用sort排序后输出dp[n-1]即可得到这个序列的LIS最大值
*/
int main(){
int n;
while(cin>>n){
cin>>a[0];
memset(dp,0,sizeof(dp));
dp[0]=1;
for(int i=1;i<n;i++){
cin>>a[i];
int max=0;
for(int j=0;j<i;j++){
if(a[j]<a[i]){
if(max<dp[j]){
max=dp[j];
}
}
}
dp[i]=max+1;
}
int ans=0;
for(int i=0;i<n;i++){
if(ans<dp[i])ans=dp[i];
}
cout<<ans<<endl;//输出LIS长度
int res=0;//以下程序用来逆序输出LIS中的元素
int j=0;
for(int i=n-1;i>=0;i--){
if(dp[i]==ans){
res=a[i];
cout<<res<<" ";
j=i;
break;
}
}
ans--;
for(int i=n-1;i>=0;i--){
if(dp[i]==ans&&a[i]<res){
res=a[i];
cout<<a[i]<<" ";
ans--;
}
}
}
}
//样例:(便于理解)
/*
7
1 4 5 3 2 7 8
1 2 3 2 2 4 5
7
3 5 4 1 6 2 9
1 2 2 1 3 2 4
*/
三、本题解法
回看本题,不难看出,这题要求的是所有的最大递减子序列个数,以样例分析,首先是A1={389,300,299,170,158},即当前最大递减子序列,删除这些,剩余A2={207,155},一共两个,这里,你可能会想到,利用LIS求法,改改程序,求递减的,每求出一个删掉,再对剩余的求,记录个数,这样确实可以,但好麻烦。 所以这里有一个更简单的方法,那就是LIS长度就是这个题的答案,即上面的代码就可以AC。
分析一波:在系统A2中至少有一个数a大于A1中的某个数,不然,这个数a完全可以加到A1中,那么A1就不是最长递减子序列了,所以从每个拦截系统中取出一个数,一定可以构成一个递增子序列,如果这个递增子序列不是最长的,,那么可以从某个系统中拿出两个数c>d,放到递增子序列中明显不满足递增条件,所以LIS的长度就是这个题的答案。