最長遞增子序列



http://qiemengdao.iteye.com/blog/1660229

I want you!

Description

Given an array Ai(0<=i<n), its length is n; We want to find an another array Bi , which is 0 or 1,and its length is n too;

Besides, Ai and Bi meets the following conditions:

If neither A[i]*B[i] nor A[j]*B[j] equals to 0, then A[i]*B[i] < A[j]*B[j];(0<=i<j<n)

Now , we want to know the maximum of ∑Bi(0<=i<n) you can get.

Input

The input consists of multiple test cases。For each test case ,the first line contains one integer n (1<n<=300).Next line contains n integers.

Output

For each case, output the maximum of ∑Bi.

Sample Input

6
1 2 3 4 5 6
4
3 2 3 6

Sample Output

6
3

將不爲0的元素提取出來求最長遞增子序列即可
#include<cstdio>
using namespace std;
int MAX(int a,int b){return a>b?a:b;}
int main(){
    int n,i,j,x,k;
    int a[301],dp[301];
    while(~scanf("%d",&n)){
        int c=0;
        for(i=0,j=0;i<n;i++){
            scanf("%d",&x);
            if(x==0)c++;
            else {
                dp[j]=1;
                a[j++]=x;
            }
        }
        int ma=0;
        for(i=1;i<j;i++){
            for(k=0;k<i;k++){
                if(a[i]>a[k]){
                    dp[i]=MAX(dp[i],dp[k]+1);
                }
            }
            ma=MAX(dp[i],ma);
        }
        printf("%d\n",ma+c);
    }
    return 0;
}

ZOJ2136最長上升子序列
參考:http://blog.csdn.net/dangwenliang/article/details/5728363
#include<cstdio>
#include<cstring>
using namespace std;
#define MAXN 1001
int main()
{
    int t;
    while(~scanf("%d",&t))
    {
        int i,j,n,a[MAXN],b[MAXN],ma;
        while(t--)
        {

            scanf("%d",&n);
            for(i=0;i<n;i++)scanf("%d",&a[i]);
       //     memset(b,1,sizeof(b));
            for(i=0;i<n;i++)b[i]=1;
            for(i=0;i<n;i++)
            {
                for(j=0;j<i;j++)
                {
                    if(a[i]>a[j]&&b[j]+1>b[i])
                        b[i]=b[j]+1;
                }
            }
            ma=0;
            for(i=0;i<n;i++)
            {
                if(b[i]>ma)ma=b[i];
            }
            printf("%d\n",ma);
            if(t)printf("\n");
        }
    }

    return 0;
}

ZOJ1986 最長公共子序列的nlogn 用二分法講複雜度從n^n降到nlogn

設A[t]表示序列中的第t個數,F[t]表示從1到t這一段中以t結尾的最長上升子序列的長度,初始時設F [t] = 
0(t = 1, 2, ..., len(A))。則有動態規劃方程:F[t] = max{1, F[j] + 1} (j = 1, 2, ..., t - 1, 且A
[j] < A[t])。
根據F[]的值進行分類。對於F[]的每一個取值k,我們只需要保留滿
足F[t] = k的所有A[t]中的最小值。設D[k]記錄這個值,即D[k] = min{A[t]} (F[t] = k)。 
注意到D[]的兩個特點: 
(1) D[k]的值是在整個計算過程中是單調不上升的。 
(2) D[]的值是有序的,即D[1] < D[2] < D[3] < ... < D[n]。 
需要證明一下
     假設d[2] >= d[3]:
      a. d[2] 在 d[3] 前面,發現d[3]前的一個元素可以代替d[2]
      b. d[2] 在 d[3] 後面,發現d[2]不成立.


  於是,主要的工作就是維護這個單調的隊列。
#include<cstdio>
#include<cstring>
using namespace std;
#define MAXN 40001
int f[MAXN],a[MAXN];
int n;
int see(int len,int value)//尋找第一個大於或等於value的下標
{
    int i,j,mid;
    i=1;
    j=len;
    while(i<=j)
    {
        mid=(i+j)/2;
        if(f[mid]>value)j=mid-1;
        else if(f[mid]<value)i=mid+1;
        else return mid;
    }
    return i;
}
int main()
{
    int t,i,j,k;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=1;i<=n;i++)scanf("%d",&a[i]);
        f[1]=a[1];
        j=1;
        for(i=2;i<=n;i++)
        {
            if(a[i]>f[j]){
                    f[++j]=a[i];
             //       printf("    1   %d %d\n",j,f[j]);
            }
            else {
                k=see(j,a[i]);
                f[k]=a[i];
           //     printf("    2   %d %d\n",k,f[k]);
            }
        }
        printf("%d\n",j);
    }
    return 0;
}








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章