POJ2533 DP入门级题目-最大上升子序列(LIS)-O(n^2)与O(nlogn) (变形,POJ1631)

来源:互联网 发布:淘宝美工一个月多少钱 编辑:程序博客网 时间:2024/05/21 07:57


0

O(nlogn)复杂度的 方法2)很重要,要掌握。


1

1)时间复杂度为O(N^2),原理是不断更新每个元素作为最后一个元素的各自序列的长度

#include <iostream>//入门DP问题,时间复杂度O(N^2)using namespace std;int main(){    int a[1010];//输入元素    int d[1010];//d[i]代表以a[i]为最后一个元素的序列的长度    int n;cin>>n;    for(int i=1;i<=n;i++){        cin>>a[i];        d[i]=1;    }    int maxn=0;    for(int i=1;i<=n;i++){        for(int j=1;j<=i-1;j++){            if(a[j]<a[i]&&d[i]<d[j]+1){//动态更新每一个元素作为最后一个元素的所构造的序列的长度                d[i]=d[j]+1;            }        }        if(d[i]>maxn)            maxn=d[i];//顺便记录最大值    }    cout<<maxn<<endl;}

2)时间复杂度为O(nlogn),构造一个数组d用来保存一个近似的最大上升子序列(不一定是真正的最长子序列,但是长度与最长子序列相同,因为每一次更新替换序列里某个数时,长度不变,序列潜力变大),用二分法查找序列里的数则降低了时间复杂度。

(即一个一个元素插入单调递增的队列,如果发现后者比当前的队尾元素大那么插入队尾,否则二分查找到比他大的最小值那个位置,替换掉即可。)

#include <iostream>#include <cstdio>using namespace std;int len; int a[1010],d[1010];int update(int k){    int l=1,r=len;    int mid;    while(l<=r){        mid=(l+r)/2;        if(d[mid]<k){            l=mid+1;        }        else if(d[mid]>k){            r=mid-1;        }        else{            return mid;        }    }    return l;//返回 l 和 返回 r 是不一样的,注意!}int main(){    int n;cin>>n;    for(int i=1;i<=n;i++){        cin>>a[i];    }    len=1;d[1]=a[1];    for(int i=2;i<=n;i++){        int position=update(a[i]);        d[position]=a[i];        if(position>len)            len++;    }    cout<<len<<endl;    return 0;}

3)疑惑???为什么同样用构造一个数组来保存近似的最大上升子序列时,但不用二分法搜,倒序遍历就会WA、??,原理同2)一样,不过时间复杂度变成O(n^2)为什么就过不了呢?1)中也是O(n^2)但是过了呀!

求解释,0.0

#include <iostream>#include <cstdio>using namespace std;int len; int a[1010],d[1010];int update(int k){    for(int j=len;j>0;j--){        if(d[j]<k){            return j+1;        }    }}int main(){    int n;cin>>n;    for(int i=1;i<=n;i++){        cin>>a[i];    }    len=1;d[1]=a[1];    for(int i=2;i<=n;i++){        int position=update(a[i]);        d[position]=a[i];        if(position>len)            len++;    }    for(int k=1;k<=len;k++)        cout<<d[k]<<" ";    return 0;}

#include <iostream>using namespace std;int main(){    int a[1010],d[1010];    int n;cin>>n;    for(int i=1;i<=n;i++){        cin>>a[i];    }    int top=1;d[1]=a[1];    for(int i=2;i<=n;i++){        if(d[top]<a[i]){//扩展序列长度            d[++top]=a[i];        }        else{//更新已经选进序列的字符,使改序列保持最大潜力            for(int j=top-1;j>0;j--){                if(d[j]<a[i]){                    d[j+1]=a[i];                    break;                }            }        }    }    cout<<top<<endl;    return 0;}



0 0
原创粉丝点击