Virus (最长上升公共子序列)

本文介绍了一种名为LCIS(最长递增子序列)的算法,该算法用于从两个受干扰的日志文件中找出可能的最长原始日志序列。通过对比两个混乱的日志记录,算法能够识别出最长的有效事件序列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

We have a log le, which is a sequence of recorded events. Naturally, the timestamps are strictly
increasing.
However, it is infected by a virus, so random records are inserted (but the order of original events
is preserved). The backup log le is also infected, but since the virus is making changes randomly, the
two logs are now different.
Given the two infected logs, your task is to nd the longest possible original log le. Note that there
might be duplicated timestamps in an infected log, but the original log le will not have duplicated
timestamps.
Input
The rst line contains
T
(
T

100), the number of test cases. Each of the following lines contains two
lines, describing the two logs in the same format. Each log starts with an integer
n
(1

n

1000),
the number of events in the log, which is followed by
n
positive integers not greater than 100,000, the
timestamps of the events, in the same order as they appear in the log.
Output
For each test case, print the number of events in the longest possible original log le.
Sample Input
1
9 1 4 2 6 3 8 5 9 1
6 2 7 6 3 5 1
Sample Output

3

算法 :LCIS算法

思想 ,可以看成一个二维数组,一个代表行,一个代表列,当a数组长度为i,b数组长度为j的时候,他们的最大的数组长度为在a【i-1】 和 b【j-1】的前提下,如果 a【i】=b【j】并且b【j】>b[j-1] 的时候,长度为 在上一个长度上 +1.

不难想到 三层 for 循环 下的上述

int a[100], b[100], c[100][100];
for(i=0;i<n;i++)
{
    for(j=0;j<m;j++)
    {
         c[i][j]=c[i-1][j-1];
         MAX=0;
         if(a[i]==b[j])
         {
            for(k=0;k<=j-1;k++)
            {
                if(b[j]>b[k] && c[i][k]>MAX)
                {
                    MAX=c[i][k];
                }
            }
            c[i][j]=MAX+1;
         }
    }
}

但是 如你所见,三层循环,可能会有超时的下场。又因为k这层的循环于j这层的循环息息相关,我们是可以把他变成二重循环的


int a[100], b[100], c[100][100];
for(i=0; i<n; i++)
{
    MAX=0;
    for(j=0; j<m; j++)
    {
        c[i][j]=c[i-1][j-1];
        if(a[i]>b[j] && c[i][j]>MAX) /*仔细琢磨一下为啥可以变成a【i】 和 b【j】 进行比较*/
        
        {
            MAX=c[i][j];
        }
        if(a[i]==b[j])
        {

            c[i][j]=MAX+1;
        }
    }
}

再继续看的话,二位数粗c[i][j] ,可以继续变为一维 的,他可以不断的更新,于是就变成了下面的这个代码

int a[100], b[100], c[100];
for(i=0; i<n; i++)
{
    MAX=0;
    for(j=0; j<m; j++)
    {
        c[j]=c[j-1];
        if(a[i]>b[j] && c[j]>MAX) /*仔细琢磨一下为啥可以变成a【i】 和 b【j】 进行比较*/
        
        {
            MAX=c[j];
        }
        if(a[i]==b[j])
        {

            c[j]=MAX+1;
        }
    }
}

(思绪可能会有点乱,有些地方没有想好怎么解释,望见谅)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
int a[1500];
int b[1500];
int dp[1500];

int main ()
{
    int n,m,i,j,k,f,t;
    cin >>t;
    while(t--)
    {
         cin >>n;
         for(i=1;i<=n;i++)
         cin >>a[i];
         cin >>m;
         for(i=1;i<=m;i++)
         cin >>b[i];
         memset(dp,0,sizeof(dp));
         for(i=1;i<=n;i++)
         {
            f=0;
            for(j=1;j<=m;j++)
            {
                if(a[i]>b[j]&& dp[j]>f)
               {
                  f=dp[j];
               }
               if(a[i]==b[j])
               {
                    dp[j]=f+1;
               }
            }
         }
         f=0;
         for(i=1;i<=m;i++)
         {
            if(dp[i]>f)
            {
                f=dp[i];
            }
         }
         cout<<f<<endl;
    }
}







评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值