蓝桥杯接龙序列
5
11 121 22 12 2023
1
暴力dfs:面对最优解问题,dfs是枚举所有方案并判断该方案是否合法,在合法方案中选出题目要的最优解。本题对于每一个数字要么留要么去,会形成一颗决策树,但o(n**2)超时。
这里注意一下数的最大值最小值求解,一个数的一对数据可以用pair存储,在写dfs时要注意剪枝:u(当前数的索引)>=n(总个数)或者 剩下的数与c(已被选)的数的总个数小于等于目前最大的答案,那么剪枝。
最后,不选一个数的情况有两个:不符合接龙条件、符合接龙条件但是不选,所以dfs(u+1,c,l);之前不能用else
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f
const int N=1e5+10;
int n,a[N],ans=0;
pair<int,int> p[N];
int f1(int a)
{
int res=0;
while(a>0)
{
res=a%10;
a/=10;
}
return res;
}
int f2(int a)
{
int res=a%10;
return res;
}
void dfs(int u,int c,int l)
{
if(u>=n)
{
ans=max(ans,c);
return;
}
if(n-u+c<=ans) return;
if(l<0||p[l].second==p[u].first)
dfs(u+1,c+1,u);
dfs(u+1,c,l);
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
int x=f1(a[i]);
int y=f2(a[i]);
p[i].first=x;
p[i].second=y;
}
dfs(0,0,-1);
cout<<n-ans<<endl;
return 0;
}
DP :是求解决策过程最优化的方法,它将大问题分解成小问题,且小问题,每个小部分之间相互联系,该部分可以受其前面一个或几个部分的影响,但是不受后面部分的影响,又称无后效性,解决问题的关键就是要找到该部分与前面部分的关系式,又称状态转移方程
本题f[i][j]表示在第i个数字之前被删掉的数字个数,其中j表示第i个数字是以j数字结尾的,因此0<=j<=9
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f
const int N=1e5+10;
int n,a[N];
pair<int,int> p[N];
int f[N][15];
int f1(int a)
{
int res=0;
while(a>0)
{
res=a%10;
a/=10;
}
return res;
}
int f2(int a)
{
int res=a%10;
return res;
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n;
a[0]=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
int x=f1(a[i]);
int y=f2(a[i]);
p[i].first=x;
p[i].second=y;
}
for(int i = 0; i < 10; i ++)
f[0][i] = 0;
for(int i = 1; i <= n; i ++)
{
//删除第i个数字
for(int j = 0; j < 10; j ++)
f[i][j] = f[i - 1][j] + 1;
//保留第i个数字
f[i][p[i].second] = min(f[i - 1][p[i].first], f[i][p[i].second]);
}
int ans = INF;
for(int i = 0; i < 10; i ++)
ans = min(ans, f[n][i]);
cout << ans << endl;
return 0;
}