POJ 2533

题目大意:

在给出的长度为m的数字序列{a[m]}中,寻找最长的上升子序列,上升子序列是指,该序列中对于任意i<j,都有a[i]<a[j]。

----------------------------------------我是华丽的分割线------------------------------------------

好吧,这一道是最长上升子序列的经典题目,为什么做这道,是我想用我在POJ1088里面学到的东西来做一下。这回是一下就过了,有进步,勉励一下自己!!奋斗

当然了,我还是用搜索做的,有了POJ1088的经验呢,发现这个的搜索空间实际上是一个相交的森林。假设每一个节点都是 原来序列中的a[i],

1.所有的父节点的序号值都小于子节点

2.所有的父节点的数值都小于子节点

3.所求的解,就是森林中最高的树的高度。

所以,算法就是,从节点i不断向下搜索(子节点序号>i,且数值>a[i]),直到到达底部节点(没有数据满足子节点的条件了),然后再退回。搜索过程中用一个数组来记录节点到目前为止的最大高度,等遍历完所有的节点以后,最后再从所有节点中选出一个高度最大的节点,它的高度就是节。

不过,这个问题的这个解法还只是递归形式的解法。从上面的表述中发现这个肯定可以用动态规划做的(根据算法导论,上面的解法就是动态规划的第二步骤的实现解法)。

先贴出递归解法:

#include <stdio.h>
#include <stdlib.h>

int *a;
int *c;
int len;

int findMax(int k){
  
  int cMax=0;
  int cTemp=0;
  int i,aTemp;
  
  aTemp=a[k];
  
  if (c[k]!=-1){  //到过的节点
    return c[k];
  }
  
  for (i=k+1;i<len;i++){
    if (a[i]>aTemp) {
    	cTemp=findMax(i)+1;
    	cMax=cTemp>cMax?cTemp:cMax;
    }
  }
  c[k]=cMax;
  return c[k];
}

int cmp_fun(const void *a,const void *b){
  return *(int *)a-*(int *)b;
}

int main(){
  int i;
  
  scanf("%d",&len);
  
  a=(int *)calloc(len,sizeof(int));
  c=(int *)calloc(len,sizeof(int));
  
  for (i=0;i<len;i++){
    scanf("%d",&(a[i]));
    c[i]=-1;
  }
  
  for (i=0;i<len;i++){
    if (c[i]==-1) findMax(i); 
  }
  
  qsort(c,len,sizeof(int),cmp_fun);

  printf("%d\n",c[len-1]+1);
}

然后是动态规划的解法:自低向上的解法

c[i]=max{ c[k] | if (a[k]<a[i] and k<i) }+1,c数组中代表最大长度。

贴代码:

#include <stdio.h>
#include <stdlib.h>

int *a;
int *c;
int len;

void findMax(){
	int cMax;
	int cTemp;
	int i,j;
	
  for (i=0;i<len;i++){
  	cMax=0;
    for (j=0;j<i;j++){
      if (a[j]<a[i]){
        cTemp=c[j]+1;
        cMax=cMax>cTemp?cMax:cTemp;
      }
    }
    c[i]=cMax;
  }
}

int cmp_fun(const void *a,const void *b){
  return *(int *)a-*(int *)b;
}

int main(){
  int i;
  
  scanf("%d",&len);
  
  a=(int *)calloc(len,sizeof(int));
  c=(int *)calloc(len,sizeof(int));
  
  for (i=0;i<len;i++){
    scanf("%d",&(a[i]));
    c[i]=-1;
  }

  findMax();
  
  qsort(c,len,sizeof(int),cmp_fun);

  printf("%d\n",c[len-1]+1);
}

好了,到此为止。

后来我在查找别人的代码的同时发现了一种用C++的STL multiset实现的方法,参考http://blog.csdn.net/qingniaofy/article/details/7857623 。对于C++不是很熟,没看懂……以后要加油啊……



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值