LIS最长上升子序列

  • 简单方法

状态设计:F[i]代表以A[i]结尾的LIS的长度

状态转移:F[i]=max{F[j]+1}(1<=j< i,A[j]< A[i])

边界处理:F[i]=1(1<=i<=n)

时间复杂度:O(n^2)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 103,INF=0x7f7f7f7f;
int a[maxn],f[maxn];
int n,ans=-INF;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) 
    {
        scanf("%d",&a[i]);
        f[i]=1;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
            if(a[j]<a[i]) f[i]=max(f[i],f[j]+1);
    for(int i=1;i<=n;i++) 
        ans=max(ans,f[i]);
    printf("%d\n",ans);
    return 0;
}
  • 贪心+二分

新建一个low数组,low[i]表示长度为i的LIS结尾元素的最小值。

对于一个上升子序列,显然其结尾元素越小,越有利于在后面接其他的元素,也就越可能变得更长

因此,我们只需要维护low数组,对于每一个a[i],如果a[i] > low[当前最长的LIS长度],就把a[i]接到当前最长的LIS后面,即low[++当前最长的LIS长度]=a[i]。
对于每一个a[i],如果a[i]能接到LIS后面,就接上去;否则,就用a[i]取更新low数组。

具体方法是,在low数组中找到第一个大于等于a[i]的元素low[j],用a[i]去更新low[j]。如果从头到尾扫一遍low数组的话,时间复杂度仍是O(n^2)。我们注意到low数组内部一定是单调不降的,所有我们可以二分low数组,找出第一个大于等于a[i]的元素。二分一次low数组的时间复杂度的O(lgn),所以总的时间复杂度是O(nlogn)。

#include <iostream>
using namespace std;
#include <cstdio>
 
const int MaxN=100001;
 
int n,i,top=0,x,stack[MaxN];
 
int main(){
    cin>>n;
    stack[top]=-1;
    for(i=1;i<=n;i++){
        cin>>x;
        if(x>stack[top]){stack[++top]=x;}
        else
        {
            int low=0,high=top,mid;
            while(low<high){
                mid=(low+high)>>1;
                if(x>stack[mid])
                    low=mid+1;
                else
                    high=mid-1;
            }
            stack[low]=x;
        }
    }
    cout<<top;
    return 0;
}

UVA10635 Prince and Princess

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<cmath>
using namespace std;
const int maxn=250*250+10;
const int INF=1e6+5;
int n,a,b;
int num[maxn],p[maxn],q[maxn];
int main()
{
    int t,x,cnt=1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&a,&b);
        memset(num,0,sizeof(num));
        int ans=0;
        for(int i=1;i<=a+1;i++)
        {
            scanf("%d",&x);
            num[x]=i;
        }
        int l=0;
        for(int i=0;i<=b;i++)
        {
            scanf("%d",&x);
            if(num[x])
            {
                p[l]=num[x];
                l++;
            }
        }
        for(int i=1;i<=l;i++)
            q[i]=INF;
        for(int i=0;i<l;i++)
        {
            int k=lower_bound(q+1,q+l+1,p[i])-q;
            q[k]=p[i];
            printf("%d %d\n",k,q[k]);
            ans=max(ans,k);
        }
        printf("Case %d: %d\n",cnt++,ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/haohaoxuexilmy/article/details/82913081