我的PAT-ADVANCED代码仓:https://github.com/617076674/PAT-ADVANCED
原题链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805437411475456
题目描述:
题目翻译:
1045 最喜欢的彩色条纹
伊娃试图用特定的颜色制作自己的颜色条纹。她希望通过切掉那些不需要的碎片并将剩下的部分缝合在一起形成她最喜欢的彩色条纹,以她最喜欢的顺序保留她最喜欢的颜色。
据说普通人眼可以区分少于200种不同颜色,因此伊娃最喜欢的颜色是有限的。然而原始条纹可能很长,而Eva希望拥有最大长度的剩余最喜欢的条纹。所以她需要你的帮助才能找到最好的结果。
请注意,解决方案可能不是唯一的,但你只需要告诉她最大长度。例如,给定条纹颜色{2 2 4 1 5 5 6 3 1 1 5 6} 如果Eva最喜欢的颜色以她最喜欢的顺序给出{2 3 1 5 6},那么她有4种可能的最佳解决方案{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),其是所涉及的颜色的总数(因此颜色从1到N编号)。然后下一行以正整数M(<= 200)开始,接着是以她最喜欢的顺序给出的M Eva最喜欢的颜色数字。最后,第三行以正整数L(<= 10 ^ 4),L代表给定条纹的长度,其后是条纹上的L种颜色。一行中的所有数字用空格分隔。
输出格式:
对于每个测试用例,只需在一行中打印出Eva最喜欢的条纹的最大长度。
输入样例:
6
5 2 3 1 5 6
12 2 2 4 1 5 5 6 3 1 1 5 6
输出样例:
7
知识点:动态规划
思路:对于伊娃喜欢的颜色,用其出现的次序来代替
以样例为例说明,伊娃喜欢的序列是2 3 1 5 6,因此2对应序号0,3对应序号1,1对应序号2,5对应序号3,6对应序号4。
将序列2 2 4 1 5 5 6 3 1 1 5 6中伊娃喜欢的数字替换为上一步所得的序号,对于不喜欢的数字则舍弃,得到序列
0 0 2 3 3 4 1 2 2 3 4。现在问题变成了求该序列的最长不下降子序列(子序列可以不连续)。
状态定义:
f(x) -------- 以x位置结尾的最长不下降子序列长度
状态转移:
初始值f(x) = 1,x = 0, 1, 2, ...
当x > 0时,f(x) = max(f(x), f(y) + 1),y = 0,1,2,...,x - 1且满足nums[y] <= nums[x]。
时间复杂度是O(n ^ 2),n为处理后序列的长度。空间复杂度是O(n)。
C++代码:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main() {
int N;
scanf("%d", &N);
int M;
scanf("%d", &M);
int position[N + 1];
fill(position, position + N + 1, -1);
int num;
for(int i = 0; i < M; i++) {
scanf("%d", &num);
position[num] = i;
}
int L;
scanf("%d", &L);
vector<int> nums;
for(int i = 0; i < L; i++) {
scanf("%d", &num);
if(position[num] == -1) {
continue;
}
nums.push_back(position[num]);
}
int dp[nums.size()];
fill(dp, dp + nums.size(), 1);
int maxIndex = 0;
for(int i = 1; i < nums.size(); i++) {
for(int j = 0; j < i; j++) {
if(nums[i] >= nums[j]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
if(dp[i] > dp[maxIndex]) {
maxIndex = i;
}
}
printf("%d\n", dp[maxIndex]);
return 0;
}
C++解题报告: