入门思路:由dfs暴力---->记忆化搜索---->递推
递归与递推
1.“递”的过程是把大问题变成小问题的过程
自顶向下
2.“归”的过程是产生答案的过程
自底向上(底指的是递归搜索树的底,是已知最小子问题的答案)
3.递推方程也可以理解为dfs的状态转移方程,是dfs向下递归的过程。
4.递归数组的初始值=递归的边界
以跳台阶题为例
1.传统dfs暴力解法(测41时耗时905ms)
if(x==1) return 1;
else if(x==2) return 2;
else return dfs(x-1)+dfs(x-2)
2.记忆化搜索优化(测41耗时1ms,优化了很多倍)
把子问题的答案存起来避免重复计算
如果要测更大的数字应该把int换成longlongint
#include<iostream>
#in clude<cstring>
#include<algorithm>
using namespace std;
const int N=20;
int n;
int men[N];
int dfs(int x)
{
if(men[x]) return men[x];
int sum=0;
if(x==1) sum=1;
else if(x==2) sum=2;
else sum=dfs(x-1) +dfs(x-2);
men[x]=sum;
return sum;
}
int main()
{
scanf("%d",&n);
int res=dfs(n);
printf("%d\n",res);
return 0;
}
3.递推的写法
是由已知最小子问题答案推到最上面的答案
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=20;
int n;
int f[N];
int main()
{ cin>>n;
f[1]=1,f[2]=2;
if(n==1||n==2)
{
cout<<f[n];
return 0;
}
for(int i=3;i<=n;i++)
{
f[i]=f[i-1]+f[i-2];
}
cout<<f[n];
return 0;
}
大盗阿福题
最优化的方法还是记忆化搜索,dfs的参数尽可能的少,不要把没有影响到边界的参数放进来
//非常暴力的写法
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
int home[N];
int n,t;
int dfs(int x)
{
if(x>n) return 0;
else return max(dfs(x+1),dfs(x+2)+home[x]);
}
int main()
{
scanf("%d",&t);
while(t--) //针对多组测试数据的情况
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&home[i]);
int res=dfs(1);
printf("%d\n",res);
}
return 0;
}
记忆化搜索写法:注意要在主函数的循环中每次都把mem 设置为0
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
int home[N];
int n,t;
int mem[N];
int dfs(int x)
{
if(mem[x]) return mem[x];
int sum=0;
if(x>n) sum=0;
else sum= max(dfs(x+1),dfs(x+2)+home[x]);
return sum;
}
int main()
{
scanf("%d",&t);
while(t--) //针对多组测试数据的情况
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&home[i]);
memset(mem,0,sizeof mem);
int res=dfs(1);
printf("%d\n",res);
}
return 0;
}
力扣:打家劫舍
状态转移方程思路:
根据第i间房子抢或者不抢来写转移方程
> 抢第i间房子,则第i-1间房子肯定是不能碰的,那么方程写为:dp[i]=dp[i-1]+nums[i];
> 不抢第i间房子,则考虑i-1间房子,不代表第i-1间房子一定要抢,则dp[i]=max(dp[i-2]+nums[i],dp[i-1])
力扣AC代码:
class Solution {
public:
int rob(vector<int>& nums) {
if(nums.size()==0) return 0;
if(nums.size()==1) return nums[0];
vector<int> dp(nums.size());
dp[0]=nums[0];
dp[1]=max(nums[0],nums[1]);
for(int i=2;i<nums.size();i++)
{
dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
}
return dp[nums.size()-1];
}
};