PAT-A-1045 Favorite Color Stripe (30 分) 动态规划--最长非降子序列 C++题解

30 篇文章 1 订阅
17 篇文章 0 订阅

1045 Favorite Color Stripe (30 分)

题目传送门:1045 Favorite Color Stripe (30 分)

一、题目大意

给定数组1、数组2,求数组2的最长的符合数组1中元素顺序的子序列。

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}.

上面是引用题目的,{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}长度都为7,且元素顺序是跟指定的数组 {2 3 1 5 6}一致的。

二、解题思路

其实乍一看感觉很像是动态规划中的经典案例:最长非降子序列。

仔细想想其实就是求最长子序列嘛,只不过这个子序列的规则不是相邻元素非降序,而是相邻元素的位置要和指定的数组中的相对位置一致。

因此用一个check数组在标记短数组的元素之间的相对位置,check[x][y]如果等于1,则表示x在y左侧,check[x][y]如果等于-1,则表示x在y右侧,如果为0,则表示x==y。

接下来就可以采用最长非降子序列的算法了,dp[i]表示以i结尾的子序列的长度,初始值是1。如果这个数a[i]不在子数组中,则不放到dp集合中进行考虑。不过在比较的时候,找出第i个数前面的check[a[j]][a[i]] != -1的j,然后就是打擂台法dp[i]=max(dp[i], dp[j]+1),dp[j]的长度加一。 详情参考下面代码:

三、AC代码

#include<bits/stdc++.h>
using namespace std;
template<typename T = int>
T read(){
	T x;
	cin >> x;
	return x;
}
int main(){
	int n =read(), m = read();
	vector<int>v(m), book(n+1);
	vector<vector<int>>check(n+1);
	for(auto &i: check){
		i.resize(n+1);
	}
	for(int i = 0; i < m; i++){
		v[i] = read();
		book[v[i]] = 1;
		for(int j = 0; j < i; j++){
			check[v[i]][v[j]] = -1; // v[i]在v[j]的左侧
			check[v[j]][v[i]] = 1; // v[j]在v[i]的右侧
		}
	}
	vector<int>a, dp;
	int l = read();
	for(int i = 0; i < l; i++){
		int x = read();
		if(!book[x])continue;
		int y = 1;
		for(int j = 0; j < a.size(); j++){
			if(check[a[j]][x] != -1){
				y = max(y, dp[j]+1);// 动态规划
			}
		}
		a.push_back(x);
		dp.push_back(y);
	}
	cout << *max_element(dp.begin(), dp.end()) << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值