zoukankan      html  css  js  c++  java
  • 8月3号的LCS,LIS,LICS:Longest Ordered Subsequence&&Common Subsequence&&Greatest Common Increasing Subsequence

    Longest Ordered Subsequence  HDU2533

    求最长递增子序列的模板:

    Slyar:属于简单的经典的DP,求最长上升子序列(LIS)。先研究了O(n^2)的思路。

    令A[i]表示输入第i个元素,D[i]表示从A[1]到A[i]中以A[i]结尾的最长子序列长度。对于任意的0 <  j <= i-1,如果A(j) < A(i),则A(i)可以接在A(j)后面形成一个以A(i)结尾的新的最长上升子序列。对于所有的 0 <  j <= i-1,我们需要找出其中的最大值。

    DP状态转移方程:

    D[i] = max{1, D[j] + 1} (j = 1, 2, 3, ..., i-1 且 A[j] < A[i])

    解释一下这个方程,i, j在范围内:

    如果 A[j] < A[i] ,则D[i] = D[j] + 1

    如果 A[j] >= A[i] ,则D[i] = 1

     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<algorithm>
     4 using namespace std;
     5 int main()
     6 {
     7     int n,i,j,MAX,dp[2005],a[2005];
     8     while(scanf("%d",&n)!=EOF)
     9     {
    10         MAX=0;
    11         for(i=0;i<n;i++)
    12             scanf("%d",&a[i]);
    13         for(i=0;i<n;i++)
    14         {
    15             dp[i]=1;
    16             for(j=0;j<i;j++)
    17                 if(a[i]>a[j]&&dp[i]<dp[j]+1)
    18                     dp[i]=dp[j]+1;
    19             if(dp[i]>MAX)
    20                 MAX=dp[i];
    21         }
    22         printf("%d
    ",MAX);
    23     }
    24     return 0;
    25 }

    还有可以用二分法找最长子序列,但具体是多少求不出。

     1 #include<iostream>
     2 #include<string.h>
     3 #include<stdio.h>
     4 #include<algorithm>
     5 using namespace std;
     6 int b[1005];
     7 int main()
     8 {
     9     int n,a,len,left,right,mid,i;
    10     while(scanf("%d",&n)!=EOF)
    11     {
    12         len=0;
    13         memset(b,0,sizeof(b));
    14         b[0]=-1;
    15         for(i=1;i<=n;i++)
    16         {
    17             scanf("%d",&a);
    18             if(a>b[len])
    19             {
    20                 len++;
    21                 b[len]=a;
    22             }
    23             else if(a<b[len])
    24             {
    25                 left=0;
    26                 right=len;
    27                 while(right-left>1)
    28                 {
    29                     mid=(left+right)/2;
    30                     if(a<=b[mid])
    31                         right=mid;
    32                     else
    33                         left=mid;
    34                 }
    35                 b[right]=a;
    36             }
    37         }
    38         printf("%d
    ",len);
    39     }
    40 }

    Common Subsequence  HDU 1159

    给出求最长公共子序列的模板:

    设两个字符串为a[]b[],dp[i][j]为a取前i个,b取前j个字符时的最大公共子序列。
    动态方程:
    if(a[i]==b[j]) dp[i][j]=dp[i-1][j-1]+1;
    else dp[i][j]=(dp[i][j-1]>p[j][i-1]?dp[i][j-1]:p[j][i-1]);
    初始化时a[i][0]=a[0][j]=0;
     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<algorithm>
     4 #include<string.h>
     5 using namespace std;
     6 char a[1005],b[1005];
     7 int dp[1005][1005];
     8 int main()
     9 {
    10     int n,m,i,j;
    11     while(scanf("%s%s",a+1,b+1)!=EOF)
    12     {
    13         n=strlen(a+1);
    14         m=strlen(b+1);
    15         memset(dp,0,sizeof(dp));
    16         for(i=1;i<=n;i++)
    17             for(j=1;j<=m;j++)
    18         {
    19             if(a[i]==b[j])
    20                 dp[i][j]=dp[i-1][j-1]+1;
    21             else if(dp[i][j-1]>dp[i-1][j])
    22                 dp[i][j]=dp[i][j-1];
    23             else
    24                 dp[i][j]=dp[i-1][j];
    25         }
    26         printf("%d
    ",dp[n][m]);
    27     }
    28     return 0;
    29 }

    Greatest Common Increasing Subsequence HDU 1423

    第三个模板:(俩者的综合)

     1     #include<iostream>
     2     #include<stdio.h>
     3     #include<algorithm>
     4     #include<string.h>
     5     using namespace std;
     6     int a[1005],b[1005],f[1005];
     7     int main()
     8     {
     9         int t,m,n,i,j,max1;
    10         scanf("%d",&t);
    11         while(t--)
    12         {
    13             scanf("%d",&m);
    14             for(i=0;i<m;i++)
    15                 scanf("%d",&a[i]);
    16             scanf("%d",&n);
    17             for(i=0;i<n;i++)
    18                 scanf("%d",&b[i]);
    19             memset(f,0,sizeof(f));
    20             for(i=0;i<m;i++)
    21             {
    22                 max1=0;
    23                 for(j=0;j<n;j++)
    24                 {
    25                     if(a[i]>b[j]&&max1<f[j])
    26                         max1=f[j];
    27                     if(a[i]==b[j])
    28                         f[j]=max1+1;
    29                 }
    30 
    31             }
    32             max1=0;
    33             for(i=0;i<n;i++)
    34                 if(f[i]>max1)
    35                     max1=f[i];
    36             printf("%d
    ",max1);
    37             if(t) printf("
    ");
    38         }
    39         return 0;
    40     }

    Palindrome HDU 1513

    回文字符:就是把它调换,求最长公共序列。

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<stdio.h>
     4 #include<string.h>
     5 using namespace std;
     6 char a[5005],b[5005];
     7 int c1[2][5005];//注意压缩路径!!减小内存(用到滚动数组):常用于DP中,因一个式子只由前面俩个或三个推出来的,所以可以压缩求出结果(但是此方法只能求出最后结果,中间的任何情况被来回的取模给淹没了!!!)
     8 int main()
     9 {
    10     int n,i,j;
    11     while(scanf("%d",&n)!=EOF)
    12     {
    13         scanf("%s",a+1);
    14         n=strlen(a+1);
    15         for(i=1;i<=n;i++)
    16             b[i]=a[n+1-i];
    17         memset(c1,0,sizeof(c1));
    18         for(i=1;i<=n;i++)
    19             for(j=1;j<=n;j++)
    20         {
    21             if(a[i]==b[j])
    22                 c1[i%2][j]=c1[(i-1)%2][j-1]+1;
    23             else if(c1[i%2][j-1]>c1[(i-1)%2][j])
    24                 c1[i%2][j]=c1[i%2][j-1];
    25             else
    26                 c1[i%2][j]=c1[(i-1)%2][j];
    27         }
    28         printf("%d
    ",n-c1[n%2][n]);
    29     }
    30     return 0;
    31 }

    魔法串 HDU 4545

    一个求最长公共子序列的变行:

    题意:多了一个条件:第二个可以字符变换。

     1 #include<iostream>
     2 #include<string.h>
     3 #include<algorithm>
     4 #include<stdio.h>
     5 using namespace std;
     6 char a[1005],b[1005],a1[2],b1[2];
     7 bool s[1005][1005];//竟然可以这么用(布尔函数)
     8 int dp[1005][1005];
     9 int main()
    10 {
    11     int d=0,t,x,n,m,i,j;
    12     scanf("%d",&t);
    13     while(t--)
    14     {
    15         scanf("%s %s",a+1,b+1);
    16         n=strlen(a+1);
    17         m=strlen(b+1);
    18         memset(dp,0,sizeof(dp));
    19         memset(s,0,sizeof(s));
    20         scanf("%d",&x);
    21         while(x--)
    22         {
    23             scanf("%s %s",a1,b1);
    24             s[a1[0]][b1[0]]=1;//这里就简化了很多步骤!!
    25         }
    26         for(i=1;i<=m;i++)
    27             for(j=1;j<=n;j++)
    28         {
    29             if(b[i]==a[j]||s[b[i]][a[j]])
    30                     dp[i][j]=dp[i-1][j-1]+1;
    31             else if(dp[i][j-1]>dp[i-1][j])
    32                 dp[i][j]=dp[i][j-1];
    33             else
    34                 dp[i][j]=dp[i-1][j];
    35 
    36         }
    37         if(dp[m][n]==n)
    38             printf("Case #%d: happy
    ",++d);
    39         else
    40             printf("Case #%d: unhappy
    ",++d);
    41     }
    42     return 0;
    43 }

    最少拦截系统 HDU 1257

    这个反映了求这类问题的核心思路:(最长递减子序列和最长递增序列在这个问题可以互换)

     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<algorithm>
     4 using namespace std;
     5 int main()
     6 {
     7     int n,i,j,MAX,dp[2005],a[2005];
     8     while(scanf("%d",&n)!=EOF)
     9     {
    10         MAX=0;
    11         for(i=0;i<n;i++)
    12             scanf("%d",&a[i]);
    13         for(i=0;i<n;i++)
    14         {
    15             dp[i]=1;
    16             for(j=0;j<i;j++)
    17             {
    18                 if(a[i]>a[j]&&dp[i]<dp[j]+1)
    19                     dp[i]=dp[j]+1;
    20             }
    21             if(dp[i]>MAX)
    22                 MAX=dp[i];
    23         }
    24         printf("%d
    ",MAX);
    25     }
    26     return 0;
    27 }

    貌似这题目太水了!!你求出最长递增子序列的长度和最长不递减子序列的长度都可以AC掉!!!

     1 #include<cstdio>
     2 
     3 int main()
     4 {
     5     int n,i,j,num,h[1000],max[1000];
     6     while(~scanf("%d",&n))
     7     {
     8         num=0;
     9         for(i=0;i<n;++i)
    10         {
    11             scanf("%d",&h[i]);
    12             max[i]=1;
    13         }
    14         for(i=1;i<n;++i)
    15             for(j=0;j<i;++j)
    16             {
    17                 if(h[j]<=h[i]&&max[j]+1>max[i])
    18                     max[i]=max[j]+1;
    19                 if(num<max[i])
    20                     num=max[i];
    21             }
    22         printf("%d
    ",num);
    23     }
    24     return 0;
    25 }

    Nested Dolls HDU 1677

    貌似这个题目和上面的类型一样,更加深刻结题思路。

     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<algorithm>
     4 #include<string.h>
     5 using namespace std;
     6 struct line
     7 {
     8     int x;
     9     int y;
    10 }a[20005];
    11 bool comp1(line a,line b)
    12 {
    13     if(a.x!=b.x) return a.x>b.x;
    14     return a.y<b.y;
    15 }
    16 int b[20005];
    17 int main()
    18 {
    19     int t,i,left,right,mid,len,n;
    20     scanf("%d",&t);
    21     while(t--)
    22     {
    23         scanf("%d",&n);
    24         for(i=0;i<n;i++)
    25             scanf("%d%d",&a[i].x,&a[i].y);
    26         sort(a,a+n,comp1);
    27         len=0;b[0]=-1;
    28         for(i=0;i<n;i++)
    29         {
    30             if(a[i].y>=b[len])
    31             {
    32                 len++;
    33                 b[len]=a[i].y;
    34             }
    35             else
    36             {
    37                 left=0;
    38                 right=len;
    39                 while(right-left>1)
    40                 {
    41                     mid=(left+right)/2;
    42                     if(b[mid]>a[i].y)
    43                         right=mid;
    44                     else
    45                         left=mid;
    46                 }
    47                 b[right]=a[i].y;
    48             }
    49         }
    50         printf("%d
    ",len);
    51     }
    52     return 0;
    53 }//二分法减少时间!

    吉哥系列故事――完美队形I   HDU 4512

    这个题目看起来好像有思路,但就无从下手!

    见大牛的:http://blog.csdn.net/freezhanacmore/article/details/9746771

    解决方法:每次枚举只重叠一个人。。。重叠的人的编号 i 从 1 到 n-1【这样就一定保证了经过后面的处理,不会出现过多的重叠】
                      那么每次求 LCIS 时 a[] 对应从 1 到 i
                                                      b[] 对应从 1 到 n-i+1
                      那么每次更新 ans 最多只可能重叠了一人。【也就是题目中说的最终完美队列中有奇数个人】
                      然后再根据所求的最大 dp[i][j] 的编号 i 和 j 判断是否重叠了
                      如果对应于当前最大的 dp[i][j] :i < n-j+1 说明当前最高的人没有重叠, ans = max(ans, dp[i][j]*2)
                                                                       否则最高的人重叠了, ans = max(ans, dp[i][j]*2-1)
     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<algorithm>
     4 #include<iostream>
     5 using namespace std;
     6 
     7 const int maxn = 210;
     8 int a[maxn], b[maxn];
     9 int dp[maxn];
    10 int n;
    11 
    12 int LCIS(int n,int m)
    13 {
    14     memset(dp,0,sizeof(dp));
    15     for(int i = 1; i <= n; i++)
    16     {
    17         int tmp = 0;
    18         for(int j = 1; j <= m; j++)
    19         {
    20             if(a[i] > b[j])
    21                 tmp = max(tmp,dp[j]);
    22             else if(a[i] == b[j])
    23                 dp[j] = max(dp[j],tmp+1);
    24         }
    25     }
    26     int ans = 0;
    27     for(int i = 1; i <= m; i++)
    28         ans = max(ans, dp[i]);
    29     return ans;
    30 }
    31 
    32 int main()
    33 {
    34     int T;
    35     scanf("%d", &T);
    36     while(T--)
    37     {
    38         scanf("%d", &n);
    39         for(int i = 1; i <= n; i++)
    40         {
    41             scanf("%d", &a[i]);
    42             b[n-i+1] = a[i];
    43         }
    44         int ans = 1;
    45         for(int i = 1; i < n; i++)
    46         {
    47             ans = max(ans, 2*LCIS(i, n-i)); //不重叠
    48             ans = max(ans, 2*LCIS(i+1, n-i)-1); //最坏恰好重叠一人
    49         }
    50         printf("%d
    ", ans);
    51     }
    52     return 0;
    53 }
  • 相关阅读:
    739. Daily Temperatures
    556. Next Greater Element III
    1078. Occurrences After Bigram
    1053. Previous Permutation With One Swap
    565. Array Nesting
    1052. Grumpy Bookstore Owner
    1051. Height Checker
    数据库入门及SQL基本语法
    ISCSI的概念
    配置一个IP SAN 存储服务器
  • 原文地址:https://www.cnblogs.com/tt123/p/3236479.html
Copyright © 2011-2022 走看看