题目链接:
蓝桥杯2023年第十四届省赛真题-接龙数列 - C语言网 (dotcpp.com)
说明:
dfs要注意,不能连上的时候绝对不选;能连上的时候可以选,也可以不选。不选的dfs分支是必须经过的过程。不是 只有不能连上才不选。
DFS代码:
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N=1e5+10;
int ans=0;
int mx=0;int n;
vector<string> s;//sequence
void dfs(int k,int cnt,char c){
if(cnt+n-k<mx) return;
if(k>=n){
if(cnt>mx){
mx=cnt;
}
return;
}
if(c==' '){
c=s[k].at(s[k].size()-1);
dfs(k+1,1,c);
dfs(k+1,0,' ');
}
else{
char mc=s[k].at(s[k].size()-1);
if(c==s[k].at(0))
dfs(k+1,cnt+1,mc);
//else 不能写else,不能连上的时候绝对不选;能连上的时候可以选,也可以不选。
//所以 这个不选的dfs 是必须经过的过程
dfs(k+1,cnt,c);
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=0;i<n;i++){
string s1;
cin>>s1;
s.push_back(s1);
}
dfs(1,1,s[0].at(s[0].size()-1));
if(mx<n-1)
dfs(1,0,' ');
cout<<n-mx;
return 0;
}
普通DP:容易想到构造以第i项为结尾的dp数组
dp[i]表示以第i项结尾的最长数列长度,状态转移方程为
dp[i]=max{dp[j]},0<j<=i,且第j项的末尾等于第k项的头部(即前i-1项所有末尾与第i项头部相同的选一个最大的)。
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N=1e5+10;
//最小的数列长度为1,不能设为0,比如长度为1时,设为0就有问题
int mx=1;
int n;
vector<string> s;//sequence
int dp[N];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
s.push_back(" ");
cin>>n;
for(int i=0;i<n;i++){
string s1;
cin>>s1;
s.push_back(s1);
}
dp[1]=1;
// mx=max(mx,dp[1]);
for(int i=2;i<=n;i++){
dp[i]=1;
for(int j=1;j<i;j++){
if(s[i].at(0)==s[j].at(s[j].size()-1))
dp[i]=max(dp[i],1+dp[j]);
}
mx=max(mx,dp[i]);
}
cout<<n-mx;
return 0;
}
优化后的DP:
因为需要选出最大的长度,dp[i]只与前i-1项中以它的首字母结尾的最长数列有关 ,所以每次保存尾部字符对应的最长序列长度是多少,这样计算dp[i]时可以直接找到以它的首字母为结尾的最长数列,就从O(n) 降到了O(1) 。
关键在于想到把一个数结尾的元素作为动态规划的递推式子的一部分(比如dp[i]的i)来考虑
代码:
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N=1e5+10;
//最小的数列长度为1,不能设为0,比如长度为1时,设为0就有问题
int mx=1;
int n;
vector<string> s;//sequence
int dp[N];
int r[N];//尾部字符对应的最长序列长度
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
s.push_back(" ");
cin>>n;
for(int i=0;i<n;i++){
string s1;
cin>>s1;
s.push_back(s1);
}
dp[1]=1;
r[s[1].at(s[1].size()-1)-'0']=dp[1];
for(int i=2;i<=n;i++){
dp[i]=1;
dp[i]=max(dp[i],1+r[s[i].at(0)-'0']);
r[s[i].at(s[i].size()-1)-'0']=max(dp[i], r[s[i].at(s[i].size()-1)-'0']) ;
mx=max(mx,dp[i]);
}
cout<<n-mx;
return 0;
}