Eva is trying to make her own color stripe out of a given one. She would like to keep only her favorite colors in her favorite order by cutting off those unwanted pieces and sewing the remaining parts together to form her favorite color stripe.
It is said that a normal human eye can distinguish about less than 200 different colors, so Eva's favorite colors are limited. However the original stripe could be very long, and Eva would like to have the remaining favorite stripe with the maximum length. So she needs your help to find her the best result.
Note that the solution might not be unique, but you only have to tell her the maximum length. For example, given a stripe of colors {2 2 4 1 5 5 6 3 1 1 5 6}. If Eva's favorite colors are given in her favorite order as {2 3 1 5 6}, then she has 4 possible best solutions {2 2 1 1 1 5 6}, {2 2 1 5 5 5 6}, {2 2 1 5 5 6 6}, and {2 2 3 1 1 5 6}.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤200) which is the total number of colors involved (and hence the colors are numbered from 1 to N). Then the next line starts with a positive integer M (≤200) followed by M Eva's favorite color numbers given in her favorite order. Finally the third line starts with a positive integer L (≤104) which is the length of the given stripe, followed by L colors on the stripe. All the numbers in a line a separated by a space.
Output Specification:
For each test case, simply print in a line the maximum length of Eva's favorite stripe.
Sample Input:
6
5 2 3 1 5 6
12 2 2 4 1 5 5 6 3 1 1 5 6
Sample Output:
7
解题思路:
题目大概意思是给出一串人物喜欢的颜色序列(用编号表示,颜色不重复),然后给出一串原始的颜色序列,除去其中不喜欢的颜色,在剩下的序列之中找出符合人物喜欢颜色序列排序的最长子序列(不要求连续,可重复,可遗漏)。
法一:
看到题目最开始想到的是递归的方法,对于已去除不喜欢颜色的序列K1,读取第一个元素
- 如果颜色是喜欢颜色序列K2的第一个颜色,那么继续往下读取。
- 如果K1[0]不等于K2[0],那么有两种可能,一是舍弃K1[0],继续往下读取。二是保留K1[0],将K2中K1[0]之前的元素都删除,继续往下读取,此时返回两种可能的最大值。
代码一:
#include <iostream>
using namespace std;
int find(int sp,int tp,int cnt,int minposition,int lastcolor);
int order[10000],q[200];//排除不喜欢颜色剩下的子序列,喜欢队列及其所在位置
int main(){
int N,M,L;
cin>>N>>M;
int i,lastcolor;
for(i=0;i<N;i++)
q[i]=-1;
for(i=0;i<M;i++){
int color;
scanf("%d",&color);
q[color-1]=i;
if(i==0)
lastcolor=color-1;
}
cin>>L;
i=0;
while(L--){
int color;
scanf("%d",&color);
if(q[color]!=-1){
order[i]=color-1;
i++;
}
}
int length=find(0,i-1,0,0,lastcolor);
printf("%d\n",length);
return 0;
}
int find(int sp,int tp,int cnt,int minposition,int lastcolor){
if(sp>tp)
return cnt;
while(q[order[sp]]<minposition){
sp++;
if(sp>tp)
return cnt;
}
if(order[sp]==lastcolor)
return find(sp+1,tp,cnt+1,minposition,lastcolor);
else {
int a=find(sp+1,tp,cnt,minposition,lastcolor);
lastcolor=order[sp];
int position=q[lastcolor];
int b=find(sp+1,tp,cnt+1,position,lastcolor);
return max(a,b);
}
}
法二:
参考了其他博主的解题思路之后,采用动态规划法求解,以减低运行时间,基本思路是首先给喜欢序列K1编号,从0至K-1,代表喜欢颜色在序列之中的位置。然后在原始颜色序列K2中除去不喜欢颜色,得到新序列K3,并构造一个新的数组K4,标号为颜色在K3序列中的位置,元素为对应颜色在K1中的位置。最后,原问题转化为在新序列K3中找到最长的非降序子序列。
构造数组dp,dp[i]表示K4从0到i的子序列中包含元素K4[i]的非递减最长子序列的长度,对于dp[i+1],其值满足:
对于,其中
且
,
最后输出最大的dp[i]
代码二:
#include <iostream>
using namespace std;
int main(){
int position[200],order[10000];
int N,K,L,cnt,i;
cin>>N>>K;
for(i=0;i<N;i++)
position[i]=-1;
for(i=0;i<K;i++){
int color;
scanf("%d",&color);
position[color-1]=i;
}
cnt=0;
cin>>L;
while(L--){
int color;
scanf("%d",&color);
if(position[color-1]>-1)
order[cnt++]=position[color-1];
}
int ans=0,dp[10000],j;
for(i=0;i<cnt;i++){
dp[i]=1;
for(j=0;j<i;j++)
if(order[j]<=order[i])
dp[i]=max(dp[i],dp[j]+1);
ans=max(ans,dp[i]);
}
printf("%d\n",ans);
}