PAT Advanced 1045 Favorite Color Stripe(DP,LIS,LCS)

链接:PAT Advanced 1045

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



题意:

给出M种颜色作为Eva喜欢的颜色(同时也给出顺序),然后给出一串长度为L的颜色序列。现在要去掉这个序列中Eva不喜欢的颜色,然后求出剩余序列的一个子序列,使得这个子序列表示的颜色顺序符合Eva喜欢的颜色的顺序(不一定要所有喜欢的颜色都出现),且为所有满足这个条件的子序列中长度最长的子序列。输出其长度。



① LIS解法:

d p [ i ] = m a x { 1 , d p [ j ] + 1 ] } = m a x { d p [ j ] } + 1         ( j ∈ [ 1 , i − 1 ] ) dp[i]=max\left \{ 1,dp[j]+1] \right \}= max\left \{ dp[j] \right \}+1 \ \ \ \ \ \ \ (j\in [1,i-1]) dp[i]=max{1,dp[j]+1]}=max{dp[j]}+1       (j[1,i1])

dp[i]:表示以第 i 个元素结尾的最长子序列的长度,最后最大的dp[i]即是答案

即找到第1个到第 i - 1 个元素能衔接在第 i 个元素前最长子序列dp[j]

所以dp[j]还需满足的条件: p o s [ 第 j 个 元 素 ] &lt; = p o s [ 第 i 个 元 素 ] pos[第j个元素]&lt;=pos[第i个元素] pos[j]<=pos[i]即第 j 个元素 在Eva喜欢的颜色顺序中 位于第 i 个元素的相同位置或其之前,才可衔接


以下代码:
#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
	int N,M,L;
	int a[210],b[10010],pos[210]={0};
	int i,j;
	scanf("%d",&N);
	scanf("%d",&M);
	for(i=1;i<=M;i++)
	{
		scanf("%d",&a[i]);
		pos[a[i]]=i;
	}
	scanf("%d",&L);
	for(i=1;i<=L;i++)
		scanf("%d",&b[i]);
	int dp[10010],ans=0;
	for(i=1;i<=L;i++)
	{
		if(pos[b[i]]==0)   //pos[b[i]]==0说明b[i]不属于Eva喜欢的颜色,直接跳过
			continue;
		dp[i]=1;           //先令dp[i]=1
		int MAX=0;         //找到可衔接的最大dp[j]
		for(j=1;j<i;j++)
		{
			if(pos[b[j]]!=0&&pos[b[j]]<=pos[b[i]])
				MAX=max(MAX,dp[j]);
		}
		dp[i]+=MAX;
		if(dp[i]>ans)       //更新最大值,即答案
			ans=dp[i];
	}
	printf("%d",ans);
	return 0;
}


②LCS解法:

该题可以视为LCS模型的一个变型。

当a[i] != b[j]时,dp[i][j] = max( dp[i][j-1] , dp[i-1][j] ),这个并没有改动。

但是当a[i] == b[j]时,不再是dp[i][j] = dp[i-1][j-1] + 1,由于允许重复元素,dp[i-1][j]或dp[i][j-1]都可能对dp[i][j]产生影响。(而dp[i-1][j-1]也会被包括,所以不用特意考虑)

最终得到状态转移方程: d p [ i ] = { m a x { d p [ i − 1 ] [ j ] , d [ i ] [ j − 1 ] } + 1 , a [ i ] = b [ j ] m a x { d p [ i − 1 ] [ j ] , d [ i ] [ j − 1 ] } , a [ i ] ≠ b [ j ] dp[i]=\left\{\begin{matrix}max\left \{ dp[i-1][j],d[i][j-1] \right \}+1,a[i]=b[j]\\max\left \{ dp[i-1][j],d[i][j-1] \right \},a[i]\neq b[j]\\ \end{matrix}\right. dp[i]={max{dp[i1][j],d[i][j1]}+1,a[i]=b[j]max{dp[i1][j],d[i][j1]},a[i]̸=b[j]


以下代码:
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
	int N,M,L;
	int a[210],b[10010];
	int i,j;
	scanf("%d",&N);
	scanf("%d",&M);
	for(i=1;i<=M;i++)
		scanf("%d",&a[i]);
	scanf("%d",&L);
	for(i=1;i<=L;i++)
		scanf("%d",&b[i]);
	vector<vector<int> > dp(M+10,vector<int>(L+10,0));
	for(i=1;i<=M;i++)
	{
		for(j=1;j<=L;j++)
		{
			if(a[i]==b[j])
				dp[i][j]=max(dp[i-1][j],dp[i][j-1])+1;
			else
				dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
		}
	}
	printf("%d",dp[M][L]);
	return 0;
}


③DAG最长路解法(记忆化搜索):

首先将数据转化为DAG,对于第 i 个元素,可以到达 其之后的 符合顺序的 元素,且边权均为1


d p [ i ] = m a x { 1 , d p [ j ] + 1 ] } = m a x { d p [ j ] } + 1         ( j ∈ [ i + 1 , L ] ) dp[i]=max\left \{ 1,dp[j]+1] \right \}= max\left \{ dp[j] \right \}+1 \ \ \ \ \ \ \ (j\in [i+1,L]) dp[i]=max{1,dp[j]+1]}=max{dp[j]}+1       (j[i+1,L])

dp[i]:表示以第 i 个元素开头的最长子序列的长度,最后最大的dp[i]即是答案


以下代码:
#include<cstdio>
#include<algorithm>
using namespace std;
int N,M,L;
int a[210],b[10010],pos[210]={0};
int dp[10010]={0};
int DP(int i)
{
	if(dp[i]>0)               //dp[i]>0说明已求出,直接返回
		return dp[i];
	dp[i]=1;
	for(int j=i+1;j<=L;j++)   //遍历所有出边
	{
		if(pos[b[j]]!=0&&pos[b[j]]>=pos[b[i]])
		{
			int temp=DP(j)+1;
			if(temp>dp[i])    //找到最大的dp[i]
				dp[i]=temp;
		}
	}
	return dp[i];
}
int main()
{
	scanf("%d",&N);
	scanf("%d",&M);
	for(int i=1;i<=M;i++)
	{
		scanf("%d",&a[i]);
		pos[a[i]]=i;
	}
	scanf("%d",&L);
	for(int i=1;i<=L;i++)
		scanf("%d",&b[i]);
	int ans=0;
	for(int i=1;i<=L;i++)   //遍历起点
	{
		if(pos[b[i]]==0)    //起点不是Eva喜欢的颜色,直接跳过
			continue;
		dp[i]=DP(i);
		if(dp[i]>ans)       //更新最大值,即答案
			ans=dp[i];
	}
	printf("%d",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值