PAT甲级——Favorite Color Stripe(最长不下降子序列问题)

最长不下降子序列问题(Longest Increasing Sequence,LIS)

在一个数字序列中,找到一个最长的子序列(可以不连续),使得这个子序列是不下降(非递减)的。

分析:

       例如现有序列A={1,2,3,-1,-1,7,9}(下标从1开始),它的最长不下降子序列是 {1,2,3,7,9},长度为5。用枚举的方法是可以求出结果的,但是每个元素选取或者不选取有两种选择,那么时间复杂度会是O(2^{^{^{}n}}),这是不能接受的。这里令dp[i]表示以i结尾的最长不下降子序列长度,在开始的时候全部初始为1。当A[j]<A[i](j<i)时,如果dp[j]+1>dp[i],那么就将dp[i]更新为dp[j]+1。但是如果A[i]之前的元素都比它大,那么A[i]就只能自己形成一条LIS,但是长度为1,即这个子序列里面只有A[i]一个元素。

要注意的是,A[i]必须和它前面的每一个元素进行比较,因为前面每一个元素的dp[j]都会对dp[i]产生可能的更新!

比如一个序列{1,5,-1,3}(下标从 1开始),A[2]=5>A[1]=1,dp[1]+1=2>dp[2]=1,那么就更新dp[2]=2;由于-1比它前面的数都小,那么dp[3]就只能是1,A[3]自己构成一个子序列;A[4]>A[1],且dp[1]+1>dp[4],那么更新dp[4]=2,A[4]<A[2],不进行子序列长度更新,A[4]>A[3],但是dp[3]+1=dp[4],所以也不用对dp[4]进行更新。这样在dp[]数组中输出最大的元素就是最长不下降子序列的长度。

#include<algorithm>
using namespace std;
const int N = 100;
int A[N], dp[N];
int main()
{
	int n;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
	{
		scanf_s("%d", &A[i]);
	}
	int ans = -1;
	for (int i = 1; i <= n; i++)
	{
		dp[i] = 1;
		for (int j = 1; j < i; j++)
		{
			if ((A[j] <= A[i])&& (dp[j] + 1 > dp[i]))
				dp[i] = dp[j] + 1;
		}
		ans = max(ans, dp[i]);
	}
	printf("%d", ans);
	return 0;
}

1045 Favorite Color Stripe

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 (≤10​4​​) 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

思路: 

        这道题还是求最长不下降子序列的问题 ,这里Eva喜欢的颜色就是所给的子序列,布条上的所有颜色就是需要在里面进行查找的数组。要注意的是,这个数组(Sample Input的第三行)里面包含了我们不需要的元素,也就是Eva不喜欢的元素,而且要查找的子序列也不是一个非下降的子序列,那么在数组输入的时候我们需要对这个数组进行处理。首先建立一个HashTable[],按照数组元素输入的顺序,令HashTable[x]=i,这样就将原来的序列映射成了一个不下降的子序列。在接收我们要进行查找的数组的时候(Sample Input的第三行),我们可以根据HashTable[x]的值是否大于等于0(初始的时候HashTable的值都为-1),来将所有需要的元素对应的Hash映射(这里是映射而不是元素本身!)存放到新的数组A[num]中去,在A[num]中查找最长不下降子序列即可。

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxc = 210;//最大颜色数
const int maxn = 10010;//最大L
int HashTable[maxc];//将喜欢的颜色序列映射为递增序列,不喜欢的颜色映射为-1
int A[maxn], dp[maxn];


int main()
{
	int n, m, x;
	scanf("%d%d", &n, &m);
	memset(HashTable, -1, sizeof(HashTable));
	for (int i = 0; i < m; i++)
	{
		scanf("%d", &x);
		HashTable[x] = i;//将喜欢的颜色按顺序映射到递增序列0,1...,m-1;
	}
	int L, num = 0;//num存放颜色序列中Eva喜欢的颜色总数
	scanf("%d", &L);
	for (int i = 0; i < L; i++)
	{
		scanf("%d", &x);
		if (HashTable[x] >= 0)
			A[num++] = HashTable[x];


	}
	//LIS问题模板
	int ans = -1;
	for (int i = 0; i < num; i++)//这里要写num,不能写成n或者m
	{
		dp[i] = 1;
		for (int j = 0; j < i; j++)
		{
			if (A[j] <= A[i] && dp[j] + 1 > dp[i])
				dp[i] = dp[j] + 1;
		}
		ans = max(ans, dp[i]);

	}
	printf("%d\n", ans);
	return 0;
}

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值