和贪心、分治一样,动态规划是一种解题的思路,而不是一个具体的算法知识点。动态规划是一种需要学习才能获得的思维方法。像贪心、分治这样的方法,在生活中,或在其他学科中有很多类似的例子,很容易联想和理解。但是动态规划不是,它是一种生活中没有的抽象计算方法,没有学过的人很难自发产生这种思路。
硬币问题
假设有五种面值的 循环五次
#include<bits/stdc++.h>
using namespace std;
const int M = 251; //定义最大金额
const int N = 5; //5种硬币
int type[N] = {1, 5, 10, 25, 50}; //5种面值
int cnt[M]; //每个金额对应最少的硬币数量
const int INF = 0x1FFFFFFF;
void solve(){
for(int k = 0; k< M; k++) //初始值为无穷大
cnt[k] = INF;
cnt[0] = 0;
for(int j = 0; j < N; j++)
for(int i = type[j]; i < M; i++)
cnt[i] = min(cnt[i], cnt[i - type[j]] + 1); //递推式
}
int main(){
int s;
solve(); //计算出所有金额对应的最少硬币数量。打表
while(cin >> s){
if(cnt[s] == INF) cout <<"No answer" << endl;
else cout << cnt[s] << endl;
}
return 0;
}
DP(动态规划)的特征
- (重叠子问题)首先,子问题是原大问题的小版本,计算步骤完全一样;其次,计算大问题的时候,需要多次重复计算小问题。这就是“重叠子问题”。 一个子问题的多次计算,耗费了大量时间。用 DPDP 处理重叠子问题,每个子问题只需要计算一次,从而避免了重复计算,这就是 DPDP 效率高的原因。具体的做法是:首先分析得到最优子结构,然后用递推或者带记忆化搜索的递归进行编程,从而实现了高效的计算。
- (最优子结构)
最优子结构的意思是:首先,大问题的最优解包含小问题的最优解;其次,可以通过小问题的最优解推导出大问题的最优解。在硬币问题中,我们把 cnt[i]的计算,减小为 cnt[i-1] 的计算,也就是把原来为i的大问题,减小为 i-1的小问题,这是硬币问题的最优子结构。
第一题 走楼梯
import java.util.Scanner;
public class Main {
private static int n;
private static int[] dp;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
dp = new int[n + 1];
fun();
}
private static void fun() {
dp[1] = 1;
dp[2] = 2;
for (int i = 3; i <= n; i++) {
dp[i] = dp[i-1] +dp[i-2];
}