动态规划 就是:给定一个问题,我们把它拆成一个个 子问题,直到子问题可以直接解决。然后把子问题的答案保存起来,以 减少重复计算 。再根据子问题答案反推,得出原问题解的一种方法。
入门思路:dfs暴力->记忆化搜索->递推DP
跳台阶
dfs暴力做法
#include <bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int n;
int dfs(int x)
{
if(x==1||x==2) return x;
else return dfs(x-1)+dfs(x-2);
}
int main()
{
scanf("%d",&n);
int res=dfs(n);
cout<<res;
return 0;
}
数据为42的时候就不能过了,用记忆化搜索来优化
记忆化搜索优化(空间换时间
#include <bits/stdc++.h>
using namespace std;
const int N=20;
int n;
int mem[N];
int dfs(int x)
{
if(mem[x]) return mem[x];//如果已经记录了直接输出
int sum=0;
if(x==1||x==2) return mem[x]=x;
else return mem[x]=dfs(x-1)+dfs(x-2);
}
int main()
{
scanf("%d",&n);
int res=dfs(n);
cout<<res;
return 0;
}
"递"的过程是 分解子问题的过程 自顶向下
"归"的过程才是 产生答案的过程 自底向上
递推DP
记忆化搜索=暴力dfs+记录答案
递推的公式=dfs向下递归的公式
递推数组的初始值=dfs递归的边界
#include <bits/stdc++.h>
using namespace std;
const int N=20;
int n;
int f[N];
int main()
{
scanf("%d",&n);
f[1]=1,f[2]=2;
if(n==1||n==2)
{
printf("%d\n",f[n]);
return 0;
}
for(int i=3;i<=n;i++)
{
f[i]=f[i-1]+f[i-2];//递推公式
}
printf("%d\n",f[n]);
return 0;
}
递推的优化,优化空间
#include <bits/stdc++.h>
using namespace std;
const int N=20;
int n;
int f[N];
int main()
{
scanf("%d",&n);
f[1]=1,f[2]=2;
if(n==1||n==2)
{
printf("%d\n",f[n]);
return 0;
}
int newf=0,tmp1=1,tmp2=2;
for(int i=3;i<=n;i++)//用三个变量进行递推,优化空间
{
newf=tmp1+tmp2;
tmp1=tmp2;
tmp2=newf;
}
/*for(int i=3;i<=n;i++)
{
f[i]=f[i+1]+f[i+2];//递推公式
}*/
printf("%d\n",newf);
return 0;
}
大盗阿福
暴力,会t
#include <bits/stdc++.h>
using namespace std;
const int N=100010;
int n,t;
int home[N];
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;
}
记忆化搜索优化
dfs传入参数过多,不利于记忆化搜索。
#include <bits/stdc++.h>
using namespace std;
const int N=100010;
int n,t;
int home[N];
int mem[N];
int dfs(int x)
{
if(mem[x]) return mem[x];
if(x>n) return mem[x]=0;
else return mem[x]=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]);
}
memset(mem,0,sizeof mem);
int res=dfs(1);
printf("%d\n",res);
}
return 0;
}
递推
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+2]=max(f[i+1],f[i]+home[i]);
}
printf("%d\n",f[n+2]);
}
return 0;
}
数字三角形
P1216 [USACO1.5][IOI1994]数字三角形 Number Triangles - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
暴力dfs
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int r;
int g[N][N];
int mem[N];
int f[N];
int dfs(int x,int y)
{
if(x>r||y>r) return 0;
else return max(dfs(x+1,y),dfs(x+1,y+1))+g[x][y];
}
int main()
{
scanf("%d",&r);
for(int i=1;i<=r;i++)
{
for(int j=1;j<=i;j++)
{
scanf("%d",&g[i][j]);
}
}
int res=dfs(1,1);
cout<<res;
return 0;
}
这里会T
记忆化搜索
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int r;
int g[N][N];
int mem[N][N];
int f[N];
int dfs(int x,int y)
{
if(mem[x][y]) return mem[x][y];
if(x>r||y>r) return mem[x][y];
else return mem[x][y]=max(dfs(x+1,y),dfs(x+1,y+1))+g[x][y];
}
int main()
{
scanf("%d",&r);
for(int i=1;i<=r;i++)
{
for(int j=1;j<=i;j++)
{
scanf("%d",&g[i][j]);
}
}
int res=dfs(1,1);
cout<<res;
return 0;
}
还是会t一个点
递推
AC代码
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int r;
int g[N][N];
int mem[N][N];
int f[N][N];
/*int dfs(int x,int y)
{
if(mem[x][y]) return mem[x][y];
if(x>r||y>r) return mem[x][y];
else return mem[x][y]=max(dfs(x+1,y),dfs(x+1,y+1))+g[x][y];
}*/
int main()
{
scanf("%d",&r);
for(int i=1;i<=r;i++)
{
for(int j=1;j<=i;j++)
{
scanf("%d",&g[i][j]);
}
}
for(int i=r;i>=1;i--)
{
for(int j=1;j<=i;j++)
{
f[i][j]=max(f[i+1][j],f[i+1][j+1])+g[i][j];
}
}
cout<<f[1][1];
return 0;
}
背包问题
记忆化搜索
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int n,m;
int v[N],w[N];//存物品的体积和价值
int mem[N][N];//记忆化搜索
//mem数组的定义:从第x个物品开始,总体积<=j的最大价值
//递推 从1-x个物品, 总体积<=j的最大价值
int dfs(int x,int spv)//从第x件物品开始,剩余容量spv,背包目前总价值sum
{
if(mem[x][spv]) return mem[x][spv];
if(x>n) return mem[x][spv]=0;//体积不够,不选
if(spv<v[x]) return mem[x][spv]=dfs(x+1,spv);
//可以选或不选
if(spv>=v[x]) return mem[x][spv]=max(dfs(x+1,spv),dfs(x+1,spv-v[x])+w[x]);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&v[i],&w[i]);
}
int res=dfs(1,m);
cout<<res;
return 0;
}
递推
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int n,m;
int v[N],w[N];//存物品的体积和价值
int mem[N][N];//记忆化搜索
int f[N][N];
int dfs(int x,int spv)//从第x件物品开始,剩余容量spv,背包目前总价值sum
{
if(mem[x][spv]) return mem[x][spv];
if(x>n) return mem[x][spv]=0;//体积不够,不选
if(spv<v[x]) return mem[x][spv]=dfs(x+1,spv);
//可以选或不选
if(spv>=v[x]) return mem[x][spv]=max(dfs(x+1,spv),dfs(x+1,spv-v[x])+w[x]);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&v[i],&w[i]);
}
//int res=dfs(1,m);
f[0][0]=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
if(j<v[i]) f[i][j]=f[i-1][j];//背包不够装
if(j>=v[i]) f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]);
}
}
cout<<f[n][m];
return 0;
}
习题
栈
P1044 [NOIP2003 普及组] 栈 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
爆炸了要,明天再说