这类问题非常简单,甚至看起来有点笨,说白了就是利用计算机的计算能力一步步算过去,也就是大多数人没有意识到的递推问题
比如求1~n的前缀和:
#include<iostream>
using namespace std;
long long sum[100];
int main(){
int n;
cin >> n;
for(int i = 1;i <= n;i ++){
sum[i] = sum[i - 1] + i;
}
cout << sum[n] << endl;
return 0;
}
比如最经典的:[NOIP2002 普及组] 过河卒 - 洛谷https://www.luogu.com.cn/problem/P1002
这个问题就是递推,或者说是动态规划,从前 到后这样一直算过去,其实这种思想一点都不难,就完全是利用了计算机的计算能力,但是为什么很多人说不会,有两点原因,一个是没有理解递推这个思想,一个是这个装态如何由上一个状态得到,这个就是间的模型少,对于第一个问题,大家看明白上述两个例子,应该就能理解的差不多了,对于第二个问题,我带着大家一起来总结一下所有的动态规划问题模型:
1背包问题:n个物品,和一个容量为v的背包,每一个物品有两个属性:价值和体积
限制是总体积小于等于背包容量,要求是价值最大,注意是可以没有必要装满
01背包:顾名思义就是每件物品能用一次或者零次(最多能用1次)
首先这类问题一看就是如果只有一件商品或者两件 或者三个都很容易选择,大问题可以分解成比较小的问题,所以是递推递归类的问题,所以说可以向动态规划这方面考虑
每个动态规划问题都是分为两个步骤,首先是状态表示,其次是状态计算
状态表示关键在于想清楚这个集合的含义的同时找到题目要求的条件和我们开始递推的条件,这两个条件是我们写代码(for循环)的关键
然后集合划分的关键在于找到能表示当前集合的子集,或者说找到这个状态的上一个状态,比如01背包问题,当前状态是选择零个还是一个产品,选不选a[i]这个产品
完全背包: 每件物品能用无限个
当前状态是选不选a[i]这个产品,这个产品选择几个的问题
多重背包:每件物品有si个 朴素版本 + 优化版本
集合划分是这个产品选择几个,最多不能超过s[i]个,朴素版本和完全背包的代码基本上是一样的,多了一个限制
优化版本是用二进制来列举每一个范围内的整数
分组背包问题:有很多组,每一组只能选择一个,水果只能选择一个,蔬菜只能选择一个
集合划分是当前组别选不选,选的话选这个里面的第几个产品