最长递增子序列的求解--动态规划求解
动态规划的基本思想(百度百科)
动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有的解。动态规划算法与类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思路。
具体的动态规划算法多种多样,但它们具有相同的填表格式
最长递增子序列问题
给定一个序列 An = a1 ,a2 , ... , an ,找出最长的子序列使得对所有 i < j ,ai < aj 。
转移方程:b[k]=max(max(b[j] | a[j]<a[k], j<k)+1,1); 如data[] = { 1, 9, 3, 8, 11, 4, 5, 6, 4, 1, 9, 7, 1, 7 }, 则data的最长递增子序列为1 3 4 5 6 9 代码如下:
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
// auxArrLen's element: the len before data[i]'s longest sequence's len
// auxArrIndex's element: the index of the maxest len in auxArrLen
// which is smaller than auxArrlen[i]'s value
int dp_lcs(int *data, int *retData, int len, int *maxLen)
{
int auxArrLen[len], auxArrIndex[len];
int i = 0, j = 0, curMaxSeqLen = 0;
int maxIndex = 0;
fill(&auxArrLen[0], &auxArrLen[len], 1);
fill(&auxArrIndex[0], &auxArrIndex[len], -1);
for(i=0; i<len; i++)
{
for(j=0; j<i; j++)
{
if(data[j]<data[i])
{
curMaxSeqLen = auxArrLen[j] + 1;
if(curMaxSeqLen>auxArrLen[i])
{
auxArrLen[i] = curMaxSeqLen;
auxArrIndex[i] = j;
}
}
}
}
//find the maxlen and the index in auxArrIndex
for(i=0; i<len; i++)
{
if(auxArrLen[i]>*maxLen)
{
*maxLen = auxArrLen[i];
maxIndex = i;
}
}
//asign the retData's elements
for(i=*maxLen-1; i>=0; i--)
{
retData[i] = data[maxIndex];
maxIndex = auxArrIndex[maxIndex];
}
}
int main(void)
{
int data[] = { 1, 9, 3, 8, 11, 4, 5, 6, 4, 1, 9, 7, 1, 7 };
int retData[10] = { 0 };
int maxLen = 0, i = 0;
const int len = 14;
dp_lcs(data, retData, len, &maxLen);
for(i=0; i<maxLen; i++)
cout << retData[i] << " ";
cout << endl;
return 0;
}