大致思路:应该属于线性DP,子序列问题,通常是去找最xx的一个最值序列(通常是最长)。
序列分为连续或者不连续,连续的有 求连续区间最大和等等,本题为不连续
通常将状态定义为dp[i]以arr[i]结尾的最长子序列这样通常是搭建子问题与原问题的桥梁
本题求去最少多少数能成为接龙序列,其实就是求最长接龙子序列
状态转移方程为
从1-i (k为迭代变量)如果能拼接上 dp[j]=max{dp[j],dp[k] + 1 };
最后得dp[n];
初始化的dp[]={1}
代码如下:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int l[100010],r[100010],dp[100010];
int main()
{
int n;
cin>>n;
for(int i=0;i<n;++i)
{
string s;
cin>>s;
l[i]=s[0]-'0',r[i]=s[s.size()-1]-'0';
}
int res=0;
for(int i=0;i<n;++i)
{
dp[i]=1;
for(int j=0;j<i;++j)
{
if(l[i]==r[j])
dp[i]=max(dp[i],dp[j]+1);
res=max(res,dp[i]);
}
}
cout<<n-res<<endl;
return 0;
}
这种复杂度是O(n^2)
当然还有另一种办法:由于接龙数列种类比较少并且由于接龙数列的特殊性
对于第i个值来说不可以不找i之前的可以直接与他匹配的因为只有一个并且总共只有10种类型(用G[N]里面存的是以i为结尾的最大值)因此可以直接通过索引去找,优化时间。
代码如下:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int g[10];//可以认识是接龙数列的种类只有10种 0,1,2,3,4,5,6,7,8,9
//存储的是以i为结尾的最大子序列长度
int main()
{
int res=0;
int n;
cin>>n;
for(int i=0;i<n;++i)
{
string s;
cin>>s;
int l=s[0]-'0',r=s[s.size()-1]-'0';
int f=max(1,g[l]+1);//求接上数列后于不接数列的最大值,
并且因为只有一种所以直接按照索引就能找个从而优化时间复杂度
g[r]=max(g[r],f);//更新或者不更新
res=max(res,f);//最终最大值的持续更新
}
cout<<n-res<<endl;
return 0;
}