题目描述
对于一个长度为 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,请你计算最少从中删除多少个数,可以使剩下的序列是接龙序列?
输入格式
第一行包含一个整数 N。
第二行包含 N 个整数 A1, A2, . . . , AN。
输出格式
一个整数代表答案。
样例输入
5 11 121 22 12 2023
样例输出
1
提示
删除 22,剩余 11, 121, 12, 2023 是接龙数列。
对于 20% 的数据,1 ≤ N ≤ 20。
对于 50% 的数据,1 ≤ N ≤ 10000。
对于 100% 的数据,1 ≤ N ≤ 105,1 ≤ Ai ≤ 109。所有 Ai 保证不包含前导 0。
解法一:仿造最长上升子序列,时间复杂度On^2.超时,二分比较麻烦,用数位来确定状态明智。
#include<bits/stdc++.h>
using namespace std;
int head(int num){ //获取高位
while(num>=10)
num/=10;
return num;
}
int main()
{
int n;
cin>>n;
int a[n];
int h[n]; //保存高位
int t[n]; //保存低位
int dp[n];
for(int i=0;i<n;i++){
cin>>a[i];
dp[i]=1;
t[i]=a[i]%10;
h[i]=head(a[i]);
}
for(int i=1;i<n;i++){
for(int j=0;j<i;j++){
if(h[i]==t[j])
dp[i]=max(dp[i],dp[j]+1); //状态转移
}
}
cout<<n-*max_element(dp,dp+n); //n-最长接龙长度
return 0;
}
解法二:
以数位为状态
#include<bits/stdc++.h>
using namespace std;
int n;int dp[10];
int main(){
cin>>n;
for(int i=0;i<n;i++){
int a;
cin>>a;
vector<int>ve;
while(a){
ve.push_back(a%10);
a/=10;
}
int x=ve.back();int y=*ve.begin(); //x高位,y低位
dp[y]=max(dp[y],dp[x]+1);//接入一个数就以y结尾
}
int len=0;
for(int i=0;i<10;++i) len=max(len,dp[i]);
cout<<n-len;
return 0;
}