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 }
  • 相关阅读:
    TongJI Online Judge预赛(3): Game
    堆栈小应用:配对
    在.net中使用Udp协议创建简单的聊天程序
    TongJI Online Judge预赛(2): LOVE LETTER
    全排列问题之递归求解
    如何打造RSS阅读器
    Html 常用标志总结
    实现页面的分帧显示
    每天OnlineJudge之 “数素数”
    文本编辑器中,如何设计 撤销/重复栈
  • 原文地址:https://www.cnblogs.com/tt123/p/3236479.html
Copyright © 2011-2022 走看看