以经典的跳楼梯问题来解析递推(dfs),记忆化搜索与递推的区别 递归 (类似于深度优先搜索dfs)(dfs属于递归的一种)记忆化搜索
递推 (ps.记忆化搜索和递推的时间复杂度都比递归小,但空间复杂度高,实现了空间换时间)(动态规划是递推的一个子集)
优化过程:最暴力的dfs–>记忆化搜索–>递推(dp )
记忆化搜索=暴力dfs+记录答案
递推的公式=dfs向上递归的公式(递推公式通常更容易理解为自底向上的递归)
递推数组的初始值=递归的边界
例题:大盗阿福
题目描述 阿福是一名经验丰富的大盗。趁着月黑风高,阿福打算今晚洗劫一条街上的店铺。
这条街上一共有 NN 家店铺,每家店中都有一些现金。阿福事先调查得知,只有当他同时洗劫了两家相邻的店铺时,街上的报警系统才会启动,然后警察就会蜂拥而至。
作为一向谨慎作案的大盗,阿福不愿意冒着被警察追捕的风险行窃。他想知道,在不惊动警察的情况下,他今晚最多可以得到多少现金?
【输入】 输入的第一行是一个整数T(T≤50)T(T≤50) ,表示一共有T组数据。
接下来的每组数据,第一行是一个整数N(1≤N≤100,000)N(1≤N≤100,000) ,表示一共有NN家店铺。第二行是NN个被空格分开的正整数,表示每一家店铺中的现金数量。每家店铺中的现金数量均不超过10001000。
【输出】 对于每组数据,输出一行。该行包含一个整数,表示阿福在不惊动警察的情况下可以得到的现金数量。
【输入样例】 2 3 1 8 2 4 10 7 6 14 【输出样例】 8 24 【提示】 对于第一组样例,阿福选择第22家店铺行窃,获得的现金数量为88。
对于第二组样例,阿福选择第11和44家店铺行窃,获得的现金数量为10+14=2410+14=24。
代码:
递归(dfs)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include<iostream> #include<algorithm> #include<cstring> using namespace std; const int N=100010; int n,T; int home[N]; //x表示当前正在考虑哪家店 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; }
记忆化搜索
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include<iostream> #include<algorithm> #include<cstring> using namespace std; const int N=100010; int mem[N]; int n,T; int home[N]; //x表示当前正在考虑哪家店 int dfs(int x){ if(mem[x]) return mem[x]; int sum=0; if(x>n) return sum=0; else return sum=max(dfs(x+1),dfs(x+2)+home[x]); mem[x]=sum; return sum; } 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; }
递推
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include<iostream> #include<algorithm> #include<cstring> using namespace std; const int N=100010; int n,T; int home[N]; int f[N]; int main(){ scanf("%d",&T); while(T--){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&home[i]); } memset(f,0,sizeof(f)); for(int i=1;i<=n;i++){ //f[i]存的是:从第1个店铺开始到第i个店铺 能洗劫到的最大价值 //f[i]=max(f[i-1],f[i-2]+home[i]);因为f[i-2]当i等于1时1-2越界,故可以给f数组的下标同时加2 f[i+2]=max(f[i+1],f[i]+home[i]); } printf("%d\n",f[n+2]); } return 0; }