2022.6.27
一、动态规划原理:
1、 最优子结构
证明问题最优解的第一个组成部分是做出一个选择;
对于一个给定问题,在其可能的第一步选择中,你界定已经知道哪种选择才会得到最优解。你现在并不关心这种选择具体是如何得到的,只是假定已经知道了这种选择;
给定可获得的最优解的选择后,确定这次选择会产生哪些子问题,以及如何最好地刻画子问题空间;
证明作为构成原问题最优解的组成部分,每个子问题的解就是它本身的最优解。方法是反证法,考虑加入某个子问题的解不是其自身的最优解,那么就可以从原问题的解中用这个子问题的最优解替换掉当前的非最优解,从而得到原问题的一个更优的解,从而与原问题最优解的假设矛盾。
2、无后效性
已经求解的子问题,不会再受到后续决策的影响。
3、子问题重叠(若不重叠,则为分治算法)
如果有大量的重叠子问题,我们可以用空间将这些子问题的解存储下来,避免重复求解相同的子问题,从而提升效率。
二、基本思路:
1、划分阶段:将原问题划分为若干阶段,每个阶段对应若干个子问题,提取这些子问题的特征(称之为状态);
2、判断状态:寻找每一个状态的可能决策,或者说是各状态间的相互转移方式(用数学的语言描述就是状态转移方程)。
3、按顺序求解每一个阶段的问题。
三、真题演练:(oiclass 1220公路乘车)
题目描述:
一个特别的单行街道在每公里处有一个汽车站。顾客根据他们乘坐汽车的公里数来付费。例如下表就是一个费用的单子。
没有一辆车子行驶超过10公里,一个顾客打算行驶n公里(1<=n<=100),它可以通过无限次的换车来完成旅程。最后要求费用最少。
输入格式:
第一行十个整数分别表示行走1到10公里的费用(<=500)。注意这些数并无实际的经济意义,即行驶10公里费用可能比行驶一公里少。
第二行一个整数n表示,旅客的总路程数。
输出格式:
仅一个整数表示最少费用。
输入样例:
12 21 31 40 49 58 69 79 90 101
15
输出格式:
147
思路:
用f数组记录答案,f[i]表示行i公里用的最少钱数。
代码:
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
int n,a[11],f[101];
int main(){
memset(f,0x7f,sizeof(f));
for(int i=1;i<=10;i++)cin >>a[i];
cin >>n;
f[1]=a[1];
for(int i=2;i<=n;i++){
for(int j=i-10;j<i;j++){
if(j<1)f[i]=min(f[i],a[i]);
else f[i]=min(f[i],f[j]+a[i-j]);
}
}
cout <<f[n];
return 0;
}