动态规划
-
状态:
-
状态转移方程:子问题的转移【下一步的决策】
-
递归【留意顺序】【利用多重循环】
-
记忆化搜索[dfs]【用数组记录值】
-
防止爆内存: 滚动数组【一层一层更新】
DAG dp【有向无环图】->起点&&终点
写完整程序:如何输出【无解的标记】
嵌套矩形问题【最长路】
-
建图【二元关系】
-
从第几个点开始
d[i]={max(d[j])+1};
- 记忆化搜索
- 起点为一
int dp(int i) { if(d[i]>0) return d[i]; d[i]=1; for(int j=1;j<=n;j++) { if(G[i][j]==1) { d[i]=max(d[i],dp[j]+1); } } return d[i]; }
- 递推
- 利用cmp&struct先进行排序
- 按顺序递归
for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++)//cmp排序之后是i-1,未排序就是n { if(G[i][j]) d[i]=max(d[i],d[j]+1); } }
- 按字典序输出
- 记忆化搜索
硬币问题
-
状态:还需要凑足的面值
-
固定起点0 和终点 S
-
递归
for(int i=1;i<=s;i++) { for(int j=1;j<=n;j++) { if(i>=v[j]) { min[i]=min(min[i],m[i-v[j]]+1); } } }
最长上升子序列
- 状态:以i为结尾的最长子序列
#include<bits/stdc++.h> using namespace std; int main() { int n; int a[6000]; cin>>n; int d[6000]; for(int i=1;i<=n;i++) { cin>>a[i]; d[i]=1; } int ma=-1; for(int i=1;i<=n;i++) { for(int j=1;j<=i-1;j++) { if(a[j]<a[i]) d[i]=max(d[i],d[j]+1);//状态转移方程 } } //不确定最大的时候最大值的出现位置 for(int i=1;i<=n;i++) { if(ma<d[i]) ma=d[i]; } cout<<ma; return 0; }
LCS
- 状态:两个长度为i和j的字符串的最大公共字符串长度
- 难点: 如何输出结果
- 类似于回溯:从末结点出发找到符合的道路
#include<bits/stdc++.h> using namespace std; int d[3005][3005]={0}; char ans[10050]; char s[10050],t[10050]; int main() { scanf("%s%s",s+1,t+1); //状态 : 两个长度为i,j的最大公共zixulie //状态转移方程 int k=strlen(s+1); int l=strlen(t+1); for(int i=1;i<=k;i++) { for(int j=1;j<=l;j++) { if(s[i]==t[j]) { if(i==0||j==0) d[i][j]=1; else d[i][j]=d[i-1][j-1]+1; } else { if(i==0) d[i][j]=0; else d[i][j]=max(d[i-1][j],d[i][j-1]); } } } while(d[k][l]>0) { if(s[k]==t[l]) { ans[d[k][l]]=s[k]; k--;l--; } else { if(d[k-1][l]==d[k][l]) {k--;} else {l--;} } } for(int i=1;i<=strlen(ans+1);i++) cout<<ans[i]; }
背包问题
-
草药问题【01背包问题】
#include<iostream> using namespace std; int main() { int t,m; cin>>t>>m; int a[1005]={0},b[1005]={0}; long long f[1005]={0}; for(int i=1;i<=m;i++) { cin>>a[i]>>b[i]; } for(int i=1;i<=m;i++) { for(int j=t;j>=a[i];j--) { f[j]=max(f[j],f[j-a[i]]+b[i]); } } cout<<f[t];//最大值在最后 return 0; }
-
-
状态
-
储存
-
二维数组:用前i个草药 背包容量为j->记忆化搜索【dp】类似于dfs的循环【return 数】
-
滚动数组:用递归的话与草药无关,只需列举背包容量
-
-
状态转移方程:f[j]=max(f[j],f[j-a[i]]+b[i])
-
重点
-
枚举的顺序
第一层:枚举草药的个数
第二层循环:
-
对于滚动数组:更新的顺序从后往前
完全背包问题:从前往后
-
-
-
最大值出现的位置:
- 二维数组:第i个草药【0…V】
- 一维数组:dp[V]
-