动态规划之最长递增子序列

一    最长递增子序列问题的描述

       设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);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值