题目大意
给两个序列,求两个序列的最大公共子序列(序列中的元素可重复)的长度
例如 {2 2 4 1 5 5 6 3 1 1 5 6}和 {2 3 1 5 6}的最大公共子序列(元素可重复)是{2 2 1 1 1 5 6}, {2 2 1 5 5 5 6}, {2 2 1 5 5 6 6}和 {2 2 3 1 1 5 6}
输入
第一行给一个正整数
N
≤
200
N\leq200
N≤200表示序列中的值的范围(
1
1
1~
N
N
N)
第二行,第一个数是正整数
M
≤
200
M\leq200
M≤200,表示第一个序列的长度,接着给出
M
M
M个数
第三行,第一个数是正整数
L
≤
1
0
4
L\leq10^4
L≤104,表示第二个序列的长度,接着给出
L
L
L个数
输出
对每个例子,在一行中输出最大公共子序列(元素可重复)的长度
样例输入
6
5 2 3 1 5 6
12 2 2 4 1 5 5 6 3 1 1 5 6
样例输出
7
解析
这题和LCS(最大公共子序列)很像,但是不同的一点是元素可重复。
其实修改LCS的状态转移方程式就可以解决元素重复的情况,ans[i][j]表示第一个序列的前i个和第二个序列的前j个的最大公共子序列(元素可重复)的长度,则状态转移方程式:
ans[i][j] = max(ans[i - 1][j], ans[i][j - 1]) if a[i] != b[j] else max(ans[i - 1][j], ans[i][j - 1]) + 1
但是这题用python写叕叒双又超时,用C++就可以AC
python:
# -*- coding: utf-8 -*-
# @Time : 2019/6/6 10:13
# @Author : ValarMorghulis
# @File : 1045.py
def solve():
n = int(input())
a = list(map(int, input().split()))
b = list(map(int, input().split()))
ans = [[0 for i in range(b[0] + 5)] for j in range(a[0] + 5)]
for i in range(1, a[0] + 1):
for j in range(1, b[0] + 1):
ans[i][j] = max(ans[i - 1][j], ans[i][j - 1]) if a[i] != b[j] else max(ans[i - 1][j], ans[i][j - 1]) + 1
print(ans[a[0]][b[0]])
if __name__ == "__main__":
solve()
C++:
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<string>
#include<cmath>
#define inf 0xffffffff
using namespace std;
int main()
{
int n, m, l;
scanf("%d", &n);
scanf("%d", &m);
int a[m+5];
memset(a, 0, sizeof(a));
for(int i=1; i<=m; i++)
scanf("%d", &a[i]);
scanf("%d", &l);
int b[l+5];
memset(b, 0, sizeof(b));
for(int i=1; i<=l; i++)
scanf("%d", &b[i]);
int ans[m+5][l+5];
memset(ans, 0, sizeof(ans));
for(int i=1; i<=m; i++)
for(int j=1; j<=l; j++)
ans[i][j]=(a[i]==b[j]?max(ans[i][j-1], ans[i-1][j])+1:max(ans[i][j-1], ans[i-1][j]));
printf("%d\n", ans[m][l]);
return 0;
}