poj 2533做题笔记

本题是求最长上升子序列(LIS)问题。

O(n^2)的思路:

 令a[i]表示第i个元素,d[i]表示从a[1]到a[i]中以a[i]结尾的最长子序列长度。对于任意的0 < j <= i-1,如果a[i]>a[j],则a[i]可以接在a[j]后面形成一个以a[i]结尾的新的最长上升子序列。

DP状态转移方程:  d[i] = max{d[i], d[j] + 1} (j = 1, 2, 3, ...,i-1 且a[j] < a[i])

解释一下这个方程,在1<=i<=n,1<=j<=i-1范围内:

默认初始化d[i] = 1,如果 a[j] <a[i] ,则d[i] = d[j] + 1

最后我们需要找出d[1~n]的最大值,即为所求。

AC代码:

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int max(int x,int y)
{
	return x>y?x:y;
}
int main()
{
	int n,i,j;
	int a[1010],d[1010];
	while(scanf("%d",&n)!=EOF)
	{
		for(i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			d[i]=0;
		}
		int maxn=0;
		for(i=1;i<=n;i++)
		{
			d[i]=1;//初始化
			for(j=1;j<i;j++)
				if(a[j]<a[i])
					d[i]=max(d[i],d[j]+1);// d[i] = max{d[i], d[j] + 1} 
			if(maxn<d[i])maxn=d[i];//求d[i]的最大值
		}
		printf("%d\n",maxn);
	}
	return 0;
}


O(nlogn)的解法:

时间复杂度降低其实是因为这个算法里面用到了二分搜索。具体操作是建立一个栈stack[],每次取栈顶元素stack[j]和读到的元素a[i]做比较,如果a[i]>stack[j] 则将a[i]入栈;否则二分查找栈中的比a[i]大的第1个数,并用a[i]替换它。最长序列长度即为栈的长度。主要注意替代时是stack[low]=a[i];

AC代码:

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;//poj2533
const int N=1010;
int main()
{
	int n,i,j;
	int a[N],stack[N];
	while(scanf("%d",&n)!=EOF)
	{
		for(i=1;i<=n;i++)
			scanf("%d",&a[i]);
		j=0;
		stack[0]=-1;
		for(i=1;i<=n;i++)
		{
			if(a[i]>stack[j])
				stack[++j]=a[i];
			else
			{
				int low=1,top=j,mid;
				while(low<=top)//二分
				{
					mid=(low+top)/2;
					if(a[i]>stack[mid])
						low=mid+1;
					else
						top=mid-1;
				}
				stack[low]=a[i];//如:在2,4,8的栈插入1或3,自己试一试
			}
		}
		printf("%d\n",j);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值