题目链接
AcWing 901. 滑雪 - AcWinghttps://www.acwing.com/activity/content/problem/content/1013/
方法介绍
有一篇博客讲的很好
记忆化搜索 —— 搜索 or 动态规划 ? - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/438406757看完后我的总结如下:
①概念介绍
记忆化搜索=深度优先搜索的实现方法+动态规划的思想
对于深度搜索的递归而言有大量的计算是重复的,如果能将这类重复计算的结果使用数组存储起来,那么就可以有效的减少计算量,降低时间复杂度。
②本题分析
比如这一题中
如果我们定义一个函数 int dfs(int x,int y)用于计算到达x,y的最长路径的长度,那么他可以从周围的四个方向演变而来,如果满足高度条件,则有
dfs(x,y)=max(dfs(x,y-1)+1,dfs(x,y+1)+1,dfs(x-1,y)+1,dfs(x+1,y)+1)
如果我们将其中一些已经计算出来的结果用数组存储起来,那么递归函数的值,可以直接返回数值,而不用重复计算。
代码实现
#include<iostream>
#include<cstring>
using namespace std;
int a[305][305];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
int h[305][305];//h[x][y]代表的含义是最后到达 x,y的最长路径长度
int R,C;
int dfs(int x,int y){//函数的含义是,计算到达x,y的最长路径长度 ---dfs的搜索的实现
if(h[x][y]!=-1){//之前以及计算过了,所以不用重复计算了
return h[x][y];
}
h[x][y]=1;//因为保存的是长度,所以长度必须大于等于1,长度的含义是区域数,自己就单独算作一共区域
for(int i=0;i<4;i++){
int xx=x+dx[i];
int yy=y+dy[i];
if(xx>=1&&xx<=R&&yy>=1&&yy<=C&&a[xx][yy]<a[x][y]){
h[x][y]=max(h[x][y],dfs(xx,yy)+1); // ---动态规划的思想
}
}
return h[x][y];
}
int main(){
int ret=-1;
cin>>R>>C;
memset(h,-1,sizeof(h));
for(int i=1;i<=R;i++){
for(int j=1;j<=C;j++){
cin>>a[i][j];
}
}
for(int i=1;i<=R;i++){
for(int j=1;j<=C;j++){
ret=max(ret,dfs(i,j));
}
}
cout<<ret;
return 0;
}
补充练习(个人觉得思想是类似的---树形DP)
题目链接
285. 没有上司的舞会 - AcWing题库https://www.acwing.com/problem/content/287/
实现代码
#include<iostream>
#include<cstring>
using namespace std;
const int N=6006;
int f[N][2];
int head[N];
int to[N],next1[N],happy[N];
int has_father[N];
int cnt=1;
void add_edge(int u,int v){//链式前向星
to[cnt]=u;
next1[cnt]=head[v];
head[v]=cnt++;
}
void dfs(int r){
f[r][1]=happy[r];//取r
for(int i=head[r];i!=-1;i=next1[i]){
int j=to[i];
dfs(j);
f[r][0]+=max(f[j][0],f[j][1]);
f[r][1]+=f[j][0];
}
}
int main(){
int n;
int root;
cin>>n;
memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++) cin>>happy[i];
for(int i=1;i<n;i++){
int x,y;
cin>>x>>y;
has_father[x]=1;
add_edge(x,y);
}
for(int i=1;i<=n;i++){
if(has_father[i]==0) root=i;
}
dfs(root);
cout<<max(f[root][0],f[root][1]);
return 0;
}
补充一个知识点:链式前向星