LCS


求最长公共子序列
核心代码:

int a[maxn];
int b[maxn];
///a,b序列,求最长公共子序列
for(int i=1;i<=n;i++)
{
   for(int j=1;j<=m;j++)
   {
      if(a[i]==b[j])
      {
         dp[i][j]=dp[i-1][j-1]+1;
      }
      else if(dp[i-1][j]>=dp[i][j-1])
      {
         dp[i][j]=dp[i-1][j];
      }
      else
      {
          dp[i][j]=dp[i][j-1];
      }
   }

记录路径:应用一个path[maxn][maxn]记录路径

for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)
            {
                if(a[i]==b[j])
                {
                    dp[i][j]=dp[i-1][j-1]+1;
                    path[i][j]=1;
                }
                else if(dp[i-1][j]>=dp[i][j-1])
                {
                    dp[i][j]=dp[i-1][j];
                    path[i][j]=2;
                }
                else
                {
                    dp[i][j]=dp[i][j-1];
                    path[i][j]=3;
                }
            }
        }

然后通过递归回溯路径
也可以直接通过一个string的二维数组 添加后面的相同元素这样子就不需要递归处理了

特别的LCS DP求法

#include<bits/stdc++.h>
   #include <iostream>
   #include<cstdio>
   #include <map>
   #include<cstring>
   using namespace std;
   #define ll long long
   #define bug(x) cout<<#x<<"=="<<x<<endl;
   const ll maxn=2e5+10;
   const int INF = 0x3f3f3f3f;
   int n;
   string b;
   char mls[20];
   int dp[maxn][20], nowl[maxn][20], nowr[maxn][20];
   int nowdp[maxn]= {0};
   int check(int l, int r,int len)
   {
       for(int i=0; i<=len; i++)
       {
           dp[0][i]=0;
           nowr[0][i]=nowl[0][i]=0;
           //全部都要初始化一下子
       }
    
       for(int i = 1; i <= n; ++i)
       {
           for(int j = 1; j <= len; ++j)
           {
               dp[i][j] = dp[i - 1][j];
    
               nowr[i][j]=nowr[i-1][j];
               nowl[i][j]=nowl[i-1][j];
    
               if(b[i] == mls[j])
               {
                   dp[i][j]++;
                   if(j == l && nowl[i][j] == 0)
                   {
                       nowl[i][j] = i;
                   }
                   else if(j == r)
                   {
                       nowr[i][j] = i;
                   }
               }
               if(dp[i][j] < dp[i][j - 1])
               {
                   dp[i][j] = dp[i][j - 1];
    
                   nowr[i][j]=nowr[i][j-1];
                   nowl[i][j]=nowl[i][j-1];
    
               }
           }
       }
       return dp[n][len];
   }
    
   void change(char l, char r)
   {
       int tot = 1;
       for(char i = '0'; i <= l; i++)
       {
           mls[tot] = i ;
           tot++;
       }
       for(char i = r; i >= l; i--)
       {
           mls[tot] = i ;
           tot++;
       }
       for(char i = r; i <='9'; i++)
       {
           mls[tot] = i ;
           tot++;
       }
       ///bug(tot);
   }
    
   int main()
   {
       int T;
       scanf("%d", &T);
       while(T--)
       {
           scanf("%d", &n);
           cin>>b;
           for(int i=0; i<n; i++)
           {
               nowdp[i]=INF;
           }
           for(int i = 0; i < n; i++)
           {
               *lower_bound(nowdp, nowdp + n, b[i]) = b[i];
           }
           int maxx = lower_bound(nowdp, nowdp + n, INF) - nowdp;
           b=' '+b;
           int ansl, ansr;
           ansl = ansr = 1;
           for(char i = '0'; i <='9'; i++)
           {
               for(char j = i + 1; j <= '9'; j++)
               {
                   change(i, j);
                   int tmp = check(i + 2-'0', j + 2-'0',12);
                   if(tmp > maxx && nowl[n][12] != 0 && nowr[n][12] != 0)
                   {
                       maxx = tmp;
                       ansl = nowl[n][12];
                       ansr = nowr[n][12];
                   }
               }
           }
           printf("%d %d %d\n", maxx, ansl, ansr);
       }
    
       return 0;
   }

赛中一直觉得是通过更改0~9的排序来更改求最长不下降子序列的问题,后来发现一个bug
0123456789->012 6543 789这样子可能6前面会存在3没有加上
所以要更改为0123 6543 6789这样子才可以计算完全!!!!!
相当重要,不然左右区间会一直计算的问题 这样子当每一次计算到达6的时候而且前面没有记录的翻转的时候更新左区间,而区间可以实现实时更新,因为左区间越小,右区间越大翻转的越多,这个就不多赘述。
所以一开始往运算法则想是有瑕疵的,应该还是抓LCS的公共字符串问题。


文章作者: Ximena
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Ximena !
  目录