分析题目:题目给出每次只可以在1~6
跳,最后选择k
个值,得出最大值。
思路:首先,最容易想到的就是DFS
暴力搜索,即选择所有的可能进行找寻,进而比较出一个最大的值。->但是会超时
暴搜:
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=1e4+9;
int a[N];
ll ans;
int n,k;
void DFS(int st,int dep,ll res){
if(dep==k){
ans=max(ans,res);
return;
}
for(int i=st+1;i<=st+6;i++){
DFS(i,dep+1,res+a[i]);
}
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>k;
ans=0x8000000000000000;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=6;i++)DFS(i,1,a[i]);
cout<<ans;
return 0;
}
这时就要想,哪里可以优化。我们可以思考一下,发现我们如果从下往上就可以存储每个以st
为起点且剩余k-dep
个数未选的最大值。在之后的向下遍寻路径中,我们判断如果result
数组不是初始值,就可以直接用,不用继续往下找了
记忆化搜索:
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=1e4+9; // 数组大小上限,用于存储输入的数字
const int M=1e3+9; // 记忆化搜索状态数组的第二维大小
const ll inf=0x8000000000000000; // 负无穷,用于初始化和比较
int a[N]; // 存储输入的数字
ll ans,result[N][M]; // ans存储最终答案,result用于记忆化搜索
int n,k; // n是数组长度,k是需要选择的数字个数
ll DFS(int st,int dep){
// 如果已经选择了k个数,直接返回当前位置的值
if(dep==k)return a[st];
// 如果已经计算过这个状态,直接返回缓存的结果
if(result[st][k-dep]!=inf)return result[st][k-dep];
// 尝试从当前位置后面1到6步内选择下一个位置
for(int i=st+1;i<=st+6&&i<=n;i++){
ll tmp=a[st]; // 当前位置的值
tmp+=DFS(i,dep+1); // 加上从下一个位置开始的最大和
result[st][k-dep]=max(result[st][k-dep],tmp); // 更新最大值
}
return result[st][k-dep]; // 返回从当前位置开始的最大和
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>k;
ans=inf; // 初始化答案为负无穷
for(int i=1;i<=n;i++)cin>>a[i];
// 初始化记忆化搜索数组
for(int i=1;i<=n;i++){
for(int j=1;j<=k;j++)result[i][j]=inf;
}
// 尝试从前6个位置开始,找出最大的和
for(int i=1;i<=6;i++)ans=max(DFS(i,1),ans);
cout<<ans; // 输出结果
return 0;
}