😊😊 😊😊
不求点赞,只求耐心看完,指出您的疑惑和写的不好的地方,谢谢您。本人会及时更正感谢。希望看完后能帮助您理解算法的本质
😊😊 😊😊
题目描述:
对于一个长度为 K 的整数数列:A1, A2, . . . , AK,我们称之为接龙数列当且仅当 Ai 的首位数字恰好等于 Ai−1 的末位数字 (2 ≤ i ≤ K)。
例如 12, 23, 35, 56, 61, 11 是接龙数列;12, 23, 34, 56 不是接龙数列,因为 56 的首位数字不等于 34 的末位数字。所有长度为 1 的整数数列都是接龙数列。
现在给定一个长度为 N 的数列 A1, A2, . . . , AN,请你计算最少从中删除多少个数,可以使剩下的序列是接龙序列?
小白到进阶各种解法:
一、暴搜:待更新😊
代码:
二、记忆化搜索:待更新😊
代码:
三、本题考察算法:最长上升子序列😊
思路:
- 本题实际上就是最长上升子序列的变种,变化的地方在于:性质上的改变。
- 最长上升子序列中是要求在当前子序列中,元素从头到尾是逐渐递增的,所加入到序列的元素都必须比当前序列末尾的元素大。而本题对于某个元素加入序列的要求是加入的元素的最高位数字要和序列末尾元素的最低位数字是相等的。
- 所以我们求的是所能拼接的子序列里面长度最长的子序列的长度。最后输出的是,中间至少要删除几个数,即最少删除几个数,使得整个合法序列最长,不如求出最长子序列的长度,然后用元素个数 - 最长子序列的长度 = 至少删除的元素。
- 本题和 此题类似:合唱队形
本题的问题分析:
5. 首先得做到枚举所有的不重不漏地枚举所有子序列。从所有子序列中寻找答案。
6. 本题中的子序列没有固定地长度,所以说需要枚举不同长度的子序列,从而造成子序列数量的庞大,所以当子序列数量众多的时候,我们可以采取将答案进行分类的情况,从而使得数据规模,逐渐变小!
7. 关键在于如何分类,分类的依据是什么?每一类的答案一定能是该类里面的所求的答案的最优解吗?常见的枚举方式有:固定右端点
i
i
i,然后枚举区间
[
1
,
i
]
[1,i]
[1,i] 中所有以第
i
i
i 个数为结尾的子序列。这可以做到不重不漏地枚举。当然也可以固定左端点去枚举所有以第
i
i
i 个点为区间起点的所有上升子序列。
代码:
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N];
int f[N]; //表示以第i个数为结尾的最长合法拼接子序列
int n;
int main()
{
cin >> n;
for (int i=1; i <= n; i ++)
cin >> a[i];
int res=0;
for (int i=1; i <= n; i ++)
{
f[i] = 1;
for (int j=1; j < i; j ++)
if (check(j, i))
f[i] = max(f[i], f[j] + 1);
res = max(res, f[i]);
}
cout << n - res << endl;
return 0;
}