zoukankan      html  css  js  c++  java
  • 序列动规

    序列动态规划

    一. 关于最长上升/下降/不上升/不下降子序列

    题目大意 :给定一个序列,求当前序列中最长上升/下降/不上升/不下降子序列(序列可以不连续)

    注 :以下算法皆由最长上升子序列展示      

      1. Ο(n2)

         思路 :f[i]表示以q[i]结尾的最长上升子序列的长度,初始值为1。每次循环1 ~ n,再循环1 ~ i - 1,如果q[i] > q[j](要上升啊),就f[i] = max(f[i], f[j] + 1)(这个 + 1是因为还要加上q[i]啊)

         code :

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int n, q[100001], f[100001], maxl;
     4 inline void memset(int a[], int b, int l)//手写memset 
     5 {
     6     for(register int i = 1; i <= l; ++i)
     7     {
     8         a[i] = b;
     9     }
    10     return;
    11 }
    12 signed main()
    13 {
    14     scanf("%d", &n);
    15     for(register int i = 1; i <= n; ++i)
    16     {
    17         scanf("%d", &q[i]);
    18     }
    19     memset(f, 1, n);//初始化 
    20     for(register int i = 1; i <= n; ++i)
    21     {
    22         for(register int j = 1; j < i; ++j)
    23         {
    24             if(q[i] > q[j])//要大于 
    25             {
    26                 f[i] = max(f[i], f[j] + 1);//取max 
    27             }
    28         }
    29         maxl = max(maxl, f[i]);//取答案最大值 
    30     }
    31     printf("%d", maxl);//最后输出的是maxl,不是f[n] 
    32     return 0;
    33 }

      2. O(n log n)

       思路 :现在不需要整f[i]了,但整一个x数组和z,z表示最长上升子序列的长度,x里存的是最长上升子序列。注意 :此时要先把x[++z] = q[1],然后循环2 ~ n,如果当前数 > x[z]那么直接插进去就好了,否则二分查找第一个大于等于它的数,然后把那个数给替换掉,其他的不变,最后输出z。

       证明 :查找出来的数是第一个大于等于它的数,那么当前数肯定比它右边的数要小(因为u(当前数) <= x(第一个比u大的数)&& x < y(x左边的数)所以 u < y)

                查找出来的数是第一个大于等于它的数,那么既然是第一个,那一定左面的数就 <= 当前数了呗

          code(直接用STL了) :

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int n, q[100001], x[100001], z;
     4 int main()
     5 {
     6     scanf("%d", &n);
     7     for(register int i = 1; i <= n; ++i)
     8     {
     9         scanf("%d", &q[i]);
    10     }
    11     x[++z] = q[1];
    12     for(register int i = 2; i <= n; ++i)
    13     {
    14         if(q[i] > x[z])
    15         {
    16             x[++z] = q[i];
    17         }
    18         else
    19         {
    20             int p = lower_bound(x + 1, x + z + 1, q[i]) - x;
    21             x[p] = q[i];
    22         }
    23     }
    24     printf("%d", z);
    25     return 0;
    26 }

    二.  关于最长公共子序列

    题目大意:给定两个字符串x,y,求两个字符串中最长公共(及两个字符相等)子序列

            思路:设f[i][j]表示x序列到第i个字符,y序列到第j个字符的最长公共子序列。这时分两种情况,一是x[i]和y[j]这两个字符相等(及可以同时选),那么答案就 等于f[i - 1][j - 1] + 1了(及从1 ~ i - 1和1 ~ j - 1中选最长公共子序列再加上1,因为还要加上x[i],y[j]这两个相等个字符啊);二是x[i] != y[j](及不能同时选,想同时选也不能同时选啊,都不同怎么同时选),那么这是会比较麻烦,因为我们只能选其一,所以我们就在两种不同的方案里取最大值——f[i][j] = max(f[i][j - 1], f[i - 1][j])。然后……就没有然后了,就完了,直接枚举x序列和y序列的长度,进行判断,看执行哪个,最后输出f[x序列的长度][y序列的长度]就OK了

            code:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int n, f[1001][1001];
     4 char x[1001], y[1001];
     5 signed main()
     6 {
     7     scanf("%s %s", x, y);
     8     int lx = strlen(x);
     9     int ly = strlen(y);
    10     for(register int i = 1; i <= lx; ++i)
    11     {
    12         for(register int j = 1; j <= ly; ++j)
    13         {
    14             if(x[i - 1] == y[j - 1])//从一开始枚举的,要减一才是正确的字符啊 
    15             {
    16                 f[i][j] = f[i - 1][j - 1] + 1;//别忘了加一 
    17             }
    18             else
    19             {
    20                 f[i][j] = max(f[i - 1][j], f[i][j - 1]);//两种情况取max,从而得到最优值 
    21             }
    22         }
    23     }
    24     printf("%d", f[lx][ly]);//最后答案在f[lx][ly]里 
    25     return 0;
    26 }
  • 相关阅读:
    解决object at 0x01DB75F0
    github导入文件操作
    git出现: not a git repository
    scrapy框架爬取妹子图片
    mysql触发器,视图,游标
    mysql锁
    在k-means或kNN,我们是用欧氏距离来计算最近的邻居之间的距离。为什么不用曼哈顿距离?
    数据库存储,索引,事务常见问题
    使用Request+正则抓取猫眼电影(常见问题)
    Tensorflow()
  • 原文地址:https://www.cnblogs.com/qqq1112/p/11129423.html
Copyright © 2011-2022 走看看