问题
题目:[拦截导弹]
思路
这个题目的本质是最长递增子序列。首先给出序列的定义,要区别子串。
在一个已知序列:
{x1,x2,...xn}
当中,取出若干数组成新的序列
{xi1,xi2,...xim}
。其中下标,
i1,i2,...im
保持递增。即新数列中各个数依旧保持原数列中的先后顺序。那么,我们称新的序列
{xi1,xi2,...xim}
为原序列的子序列。若在子序列当中,当
ix<iy
时,有
xix<xiy
。那么我们称这个子序列为原序列的一个递增子序列。
注意:
子序列和子串的区别就是,前者下标不连续,而后者下标连续
最长递增子序列问题就是,在一个给定的序列中,求得一个最长的递增子序列。
- 状态定义
dp[i]表示以i结尾的递增子序列的长度 - 转移函数
dp[i]={1,max{1,dp[j]+1|j<i∧arr[j]<arr[i]},i=0i>0(1) - 初始化
dp[0]=1(2) - 打表
代码
本题,是最长递减子序列。转移函数修改就好了。
#include <iostream>
#include <fstream>
#include <cstring>
//#define LOCAL
#define N 25
int dp[N + 5];
int arr[N + 5];
int cal_lis( const int* arr, int n );
int main( void )
{
#ifdef LOCAL
std::ifstream cin( "input.dat" );
#endif
int n = 0;
while( std::cin >> n )
{
for( int i = 0; i < n; ++i )
{
std::cin >> arr[i];
}
int ans = cal_lis( arr, n );
std::cout << ans << std::endl;
}
#ifdef LOCAL
cin.close();
#endif
return 0;
}
int cal_lis( const int* arr, int n )
{
if( NULL == arr || n <= 0 )
return -1;
std::memset( dp, 0, sizeof(dp) );
dp[0] = 1;
int max = 1;
for( int i = 1; i < n; ++i )
{
dp[i] = 1;
for( int j = 0; j < i; ++j )
{
if( arr[j] >= arr[i] )
{
if( dp[j] + 1 > dp[i] )
dp[i] = dp[j] + 1;
}
}
if( dp[i] > max )
max = dp[i];
}
return max;
}