动态规划--最长递增子序列(LIS)-最长公共子序列(LCS)
LIS
最长递增子序列,朴素的是o(n^2)算法,二分下可以写成o(nlgn):维护一个当前最优的递增序列——找到恰好大于它更新
LCS
最长公共子序列,通常o(n^2)的算法
********************************************************************************************************************
LIS:
题目大意:给定序列个数n及n个数,求该序列的最大连续子序列的和,要求输出最大连续子序列的和以及子序列的首位位置
解题思路:经典DP,可以定义
dp[i]表示以a[i]为结尾的子序列的和的最大值,因而最大连续子序列及为dp数组中的最大值。
状态转移方程:dp[1] = a[1]; //以a[1]为结尾的子序列只有a[1];
i >= 2时, dp[i] = max( dp[i-1]+a[i], a[i] );
/* HDU 1003 Max Sum --- 经典DP */
#include <cstdio>#include <cstring>
int dp[100005];
int main()
{
int t, n;
int kase = 0;
int fst, lst, maxSum; //记录首位位置以及最大和
int start; //start是用于记录中间变化的起点的
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
for (int i = 0; i < n; ++i)
{
scanf("%d", dp + i);
}
start = fst = lst = 0;
maxSum = dp[0];
for (int i = 1; i < n; ++i)
{ //dp[i] = MAX(dp[i - 1] + dp[i], dp[i]);
if (dp[i - 1] >= 0)
{
dp[i] = dp[i - 1] + dp[i];
}
else
{
start = i; //抛弃dp[i-1],则起点发生变化 }
if (dp[i] > maxSum)
{ //若当前求得的子序列和最大,进行更新
maxSum = dp[i];
fst = start;
lst = i;
}
}
if (kase)
{
printf("\n");
}
printf("Case %d:\n", ++kase);
printf("%d %d %d\n", maxSum, fst + 1, lst + 1);
}
}
return 0;
}
例: