Poj 2533
求一段最长的上升子序列的长度(ps不是非降序列,注意,因为这个就要求你找到的后边一项一定大于前边的),在这里我提供两种思路,一种是DP,最普遍的思路,时间复杂度为0(n^2),另外一种是利用到栈的思想和二分,时间复杂度为0(nlgn)相对来说,如果给的数据n越大,那么这个第二种方法的有事就体现出来了,所以我希望读者能够把第二种思路掌握好,方便解题。
#include
#include
#include
#include
int a[300],dp[500];
int id;
using namespace std;
int main()
{
int n;scanf("%d",&n);
int ans=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
memset(dp,0,sizeof dp);
//id=1;
for(int i=1;i<=n;i++)
{
dp[i]=1;
for(int j=i-1;j>=1;j--)
if(a[i]>a[j])
if(dp[j]+1>dp[i])
{
dp[i]=dp[j]+1;
}
if(dp[i]>ans)
{
ans=dp[i];
//id=i;
}
}
cout<
这个是dp,还有个栈的思想,但是不一定要用到栈:
#include
#include
//#include
int s[10000],t,n;
using namespace std;
int main()
{
int top=0;
scanf("%d",&n);
scanf("%d",&t);
top=0;
s[0]=t;
top++;
for(int i=1;i
scanf("%d",&t);
if(t>s[top-1])//如果发现要进去的数比栈顶元素大,直接进栈
{
s[top++]=t;
}
else//否则就这样
{
int left=0,right=top;//使用二分找到这个站里边比temp大的最小的那个数s[left];
while(left
int mid=(left+right)>>1;
if(s[mid]<=t)left=mid+1;
else {right=mid;}
}
s[left]=t;
}
}
printf("%d\n",top);//最后结果就是我们需要的这个站的长度
}
//8
//1 5 8 2 4 9 1 10
但是在输出的时候就只能用第一种方法了(dp),打个最简单的比方,如1,5,8,2这几个数,如果按照第二种方法,那么结果就是1,5,8按照顺序进栈,然后2发现比8小,就在站里边找到一个比2大的最小的一个数,那就是5,然后把5替换掉,变成1,2,8,结果就是3,但是真真的序列应该是1,5,8,这个时候最长的序列的个数是一样的,但是吧里边的值给改了,所以这就不能用于输出,下边,我来写个用于dp的输出:这里重点在pre的函数的应用
#include//1 5 8 2 4 9 1 10
最后希望我的总结对你有所帮助,么么哒,我一开始也是什么都不会,慢慢的只要你努力,那么你就会发现会与不会并没有那一墙之隔,只有那么一念之差,最后一句话,只要你想学,没有什么你是学不会的,真的!加油,ACMer!