听说这个这个呢~~~是动态规划的典型类题,叫最长上升子序列(LIS),但这个题是最长不上升子序列,原理一样哈,那就来分析一下~~
LIS:
有一串数,比如1 3 5 7 9 2 4 6 8,求最长上升子序列中,元素的个数。
分析的方法,据说叫贪心``就是化大为小:设一个dp数组,来记录每一个元素和它之前的所有元素组成的最长上升子序列中元素的个数,可以看到子问题和原问题是相同的,只是规模(N)变小了,解题方法是由小规模的结果推出原规模的结果,这叫不叫递归呢...?有点像..
S1:从第一个元素开始,只有他自己,所以dp[1]=1;
s2:第二个元素和它之前的,因为1 3组成了上升序列,所以dp[2]=2
s2,第三个元素和它之前的,1,3,5,因为1 3 5,上升,所以dp[3]=2;
以此类推,过了9时,dp[5]=5;
s6:元素为2,9>2结束了上升,但并不意味着dp[6]=dp[5]=5,因为2之前,比它小且组成上升的,只有第一个元素1,所以这里dp[6]=2
……
所以dp[]为:1 2 3 4 5 2 3 4 5
我原来错在,以为dp[i]=dp[i-1]+(0 or 1),呃..是没理解这种算法的含义
现在知道了,每个元素的dp值,是仅比它小的元素的dp值+1,比如第8个元素6,仅比它小的是5,而5的dp为3,加1就是6的dp值:4。说白点呢,就是因为要求的是上升序列,目标元素(设为j,i && j < i),若前j个是上升状态,那么加上i以后,就变成前i个都是上升状态,自然dp值是要加上1的。
==============================================
就导弹拦截这个题呢,虽然是最长不上升序列,但道理都是一样的,解决起来改两个地方就可以了
1,再用一个数组存逆序,把下降变成上升求就好了
2,注意多了个等号,300 300时,dp是要加一的
下面两段代码,第一个是这个题的,第二个是我自己写的LIS,嘻嘻~~~开心开心
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <algorithm>
using namespace std;
int num1[100];
int num2[100];
int n;
int nlis() //not lis~~
{
int dp[100];
int i, j;
int each_e_dp;
int max_dp;
memset( dp,0,sizeof(dp) );
dp[1] = 1;
each_e_dp = 0;
for (i = 2 ; i <= n ; i++)
{
for (j = 1 ; j < i ; j++)
{
if (num2[j] <= num2[i] && each_e_dp < dp[j]) //等号注意不能掉
{
each_e_dp = dp[j];
}
}
dp[i] = each_e_dp + 1;
each_e_dp = 0;
}
max_dp = 0; //求最大dp,快排,起泡,怎么都行,数据不大。
for ( i = 1 ; i <=n ; i++)
{
if ( dp[i] > max_dp )
{
max_dp = dp[i];
}
}
return max_dp;
}
int main()
{
int k;
int i;
int max_dp;
k = 1;
memset(num1,0,sizeof(num1));
memset(num2,0,sizeof(num2));
while(scanf("%d", &n ) != EOF)
{
for(i = 1; i <= n; i++)
{
scanf("%d", &num1[i]);
}
for(i = n; i >= 1; i--)
{
num2[k++] = num1[i]; //逆序,讲问题变为LIS
}
k = 1;
max_dp = nlis();
printf("%d\n", max_dp);
}
return 0;
}
============================================
下面是LIS~~
//LIS,最长上升子序列
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <algorithm>
using namespace std;
int main()
{
int dp[100];
int num[100];
int n, i, j;
int max_dp = 0;
int each_e_dp = 0;
while( scanf("%d", &n) != EOF )
{
memset(dp,0,sizeof(dp));
memset(num,0,sizeof(num));
for (i = 1; i <= n; i++)
{
scanf("%d", &num[i]);
}
dp[1] = 1;
each_e_dp = 0;
for (i = 2 ; i<= n ; i++)
{
for (j = 1; j < i ; j++)
{
if ( num[j] < num[i] && each_e_dp < dp[j] )
{
each_e_dp = dp[j];
}
}
dp[i] = each_e_dp + 1;
each_e_dp = 0;
}
for (i = 1 ; i <= n ; i++)
{
if (dp[i] > max_dp)
{
max_dp = dp[i];
}
}
printf("%d\n", max_dp);
max_dp = 0;
}
system("pause");
return 0;
}