当说到求最长上升自序列问题时,一般人都会想到用动态规划来求解
笔者当时遇到这个问题时,并没有学习动态规划,所以想出了另一种解决方案
下面笔者将介绍一种用回溯法求解最长上升序列问题
先看程序效果:
例一:以序列 2,1,3,5,9,4,8 为例,可以看出其最长上升自序列为:
1 3 4 8
1 3 5 8
1 3 5 9
2 3 4 8
2 3 5 8
2 3 5 9
下面开始讲解此算法:
由于此方法要用到后续数,首先给出一个后续数的定义
后续数:以当前元素开始的子序列的最长上升子序列元素的个数减一
求一个数的后续数的方法:从这个元素开始向后查找元素值比它大并且后续数最大的元素的后续数加一,如果它后面没有比它小的元素,则其后续数为零
定义读起来有点拗口,下面笔者举例来说明
还是一序列 2 ,1,7,3,5,9,4,8为例:
8的后续数为0,因为8后面没有比它大的元素
4的后续数为1,因为8比4大,4的后续数就是8的后续数加1;
9的后续数为0,因为9后面没有比它大的元素;
3的后续数为2,因为3 的后续数可以是4的后续数(后续数为1)加1或者是5的后续数(后续数为1)加1。即是2
1的后续数为3,因为1元素后面后续数最大的元素是2,则1的后续数就是2的后续数(后续数为2)加1,即是3
可以依次求得每个元素的后续数:
元素 后续数
8 0
4 1 (0+1)
9 0
5 1 (0+1)
3 2 (1+1)
7 1 (0+1)
1 3 (2+1)
2 3 (2+1)
如下图所示,连线右边的元素大于左边的元素,并且其后续数等于左边元素的后续数减1
因此,即求得了所有的最长上升自序列
相关代码如下:
#include"stdio.h"
#define M 50 //宏定义元素个数有50个
#define N 50
struct node
{
int num; //存放元素
int last; //存放元素的后续数
}a[M],b[M];
int OutCont=0;
int count=0; //存储用户输入的元素个数
int houXu=0; //存储最长后续数
void huidai(struct node a[],int q) //把組成最長上升序列的元素以树的形式連接起來
{
for(int i=q+1;i<=count;i++)
{
if(a[i].num>a[q].num && a[i].last+1==a[q].last)
{
b[OutCont]=a[i];
if(0==a[i].last)
{
for (int j=0; j<OutCont+1;j++)
{
printf("%d",b[j].num);
}
printf("\n");
}
else
{
++OutCont;
huidai(a,i);
--OutCont;
}
}
}
}
int main()
{
int t,q;
printf("请输入序列中元素的个数:");
scanf("%d",&count);getchar();
printf("请输入序列元素,用空格隔开:");
for(int i=1;i<=count;i++) //用数组a[]来存放数,从a[1]开始存放
{
scanf("%d",&a[i].num);
}
for(i=0;i<=count;i++) //后续数清零
a[i].last=0;
for(int j=count-1;j>0;j--) //将每个元素的后续数求出
{ t=0;
for(int i=j+1;i<=count;i++)
{
if(a[i].num>a[j].num&&a[i].last>=a[0].last)
{
a[0].num=a[j].num;
a[0].last=a[i].last;
t=1;
}
}
if(t==1)a[j].last=a[0].last+1;
}
a[0].last=0;
for(i=0;i<=count;i++) //求出最长后续数,将其存放到houXu中
if(a[i].last>=houXu)
{
houXu=a[i].last;q=i;
}
printf("\n最长上升序列的长度为:%d\n",houXu+1);//將最长上升序列的个数输出
printf("上升序列为:\n");
for (i=1;i<=count;i++)
{
if(a[i].last==houXu)
{
b[OutCont]=a[i];
++OutCont;
huidai(a,i);
--OutCont;
}
}
getchar();
return 0;
}
欢迎大家转载,如有转载请注明文章来自: http://blog.youkuaiyun.com/q345852047