一 最长递增子序列问题的描述
设L=<a1,a2,…,an>是n个不同的实数的序列,L的递增子序列是这样一个子序列Lin=<aK1,ak2,…,akm>,其中k1<k2<…<km且aK1<ak2<…<akm。求最大的m值。
第一种算法:转化为LCS(最长公共子序列)问题求解
设序列X=<b1,b2,…,bn>是对序列L=<a1,a2,…,an>按递增排好序的序列。那么显然X与L的最长公共子序列即为L的最长递增子序列。这样就把求最长递增子序列的问题转化为求最长公共子序列问题LCS了。
第二种算法:动态规划法
设f(i)表示L中以ai为末元素的最长递增子序列的长度。则有如下的递推方程:
f[i] = max(max(f[j] | a[j] < a[i], j < k)+1, 1);
这个递推方程的意思是,在求以ai为末元素的最长递增子序列时,找到所有序号在L前面且小于ai的元素aj,即j<i且aj<ai。如果这样的元素存在,那么对所有aj,都有一个以aj为末元素的最长递增子序列的长度f(j),把其中最大的f(j)选出来,那么f(i)就等于最大的f(j)加上1,即以ai为末元素的最长递增子序列,等于以使f(j)最大的那个aj为末元素的递增子序列最末再加上ai;如果这样的元素不存在,那么ai自身构成一个长度为1的以ai为末元素的递增子序列。
代码如下:
//动态规划
//最长递增子序列
#include<stdio.h>
#include<malloc.h>
#include<assert.h>
void Fun(int *p, int n);
int main()
{
int n;
int *p;
int i;
printf("请输入序列的长度\n");
scanf("%d", &n);
p = (int *)malloc(sizeof(int) * n);
assert(p != NULL);
printf("输入序列的值\n");
for(i = 0; i < n; ++i)
scanf("%d", p+i);
Fun(p, n);
free(p);
return 0;
}
void Fun(int *p, int n)
{
void Print(int *p, int *Res, int n, int max);
void Print1(int *p, int *Res, int n, int max);
int *q;//保存公共子序列的长度
int *Res;//回溯时寻找要输出的元素
int max = 0;
int i, j;
q = (int *)malloc(sizeof(int) * n);
assert(q != NULL);
Res = (int *)malloc(sizeof(int) * n);
assert(Res != NULL);
for(i = 0; i < n; ++i)
q[i] = 1;
for(i = 0; i < n; ++i)
Res[i] = -1;
for(i = 1; i < n; ++i)
{
max = 0;
for(j = 0; j < i; j++)
{
if(p[i] > p[j] && max < q[j])
{
max = q[i];
Res[i] = j;
}
q[i] = max + 1;
}
}
j = 0;
max = 0;
for(i = 0; i < n; ++i)
if(max < q[i])
{
max = q[i];
j = i;
}
printf("最长递增子序列的长度为%d\n", max);
for(i = 0; i < n; ++i)//观察结果
printf("%d ", q[i]);
printf("\n");
for(i = 0; i < n; ++i)//观察结果
printf("%d ", Res[i]);
printf("\n");
// Print(p, Res, j, max);
Print1(p,Res, j, max);
free(Res);
}
void Print(int *p, int *Res, int n, int max)//递归回溯输出子序列
{
if(max < 1)
return;
Print(p, Res, Res[n], max-1);
printf("%d ", p[n]);
}
void Print1(int *p, int *Res, int n, int max)//非递归回溯输出子序列
{
int *temp;
int pos;//子序列中元素在p中的位置
int i ;
int count = max;
temp = (int *)malloc(sizeof(int) * max);
assert(temp != NULL);
i = max -1;
temp[i] = p[n];
max--;
while(max > 0 && i >= 0)
{
pos = Res[n];
temp[--i] = p[pos];
n = pos;
max--;
}
assert(max == 0 && i <= 0);
for(i = 0; i < count; ++i)
printf("%d ", temp[i]);
printf("\n");
free(temp);
}