要点1,f(x)意思为,凑够x元所需要最少的硬币个数,这是一种映射。就是dp【i】的含义.
要点2,f(11)=min(f(11-5),f(11-2),f(11-1))+1.其中f(11)是由f(10),f(9),f(6)这三种状态一步转移过来的。
同理,将继续从上往下推,直到f(1),可用递归,但是每次遇到同样的f(x)都会再算一遍。所以用动态规划正着来计算(空间换时间),从f(1)
一直算到f(11),遇到x较大时,dp记录这x较小的f(x)值,直接拿来用。
要点三,边界,当x-ci《0,即要凑11元,给的面值为1,2,5,20,其中c4=20就大于x ,此时将f(c4)置为大值,正无穷或者x+1(aim+1),这样再取最小值的时候min (f(),f)时永远都取不到。
classSolution {
public:
intminMoney(vector<int>& arr, intaim) {
//小于1的都返回0
if(aim < 1)
return0;
//dp[i]表示凑齐i元最少需要多少货币数
vector<int> dp(aim + 1, aim + 1); //取比原长度大1,每个值置为最大值+1,dp【11】,???????????????????
dp[0] = 0; //dp【0】=0,凑0元需要0枚硬币
//遍历1-aim元
for(inti = 1; i <= aim; i++){//从小到达计算至dp【11】
//每种面值的货币都要枚举
for(intj = 0; j < arr.size(); j++){//对凑f(i),每个货币都要试一下,即f(1)=min(f(1-5),f(1-2),f(1-1))+1------此处可见初始化为aim+1的好处,
再代码种随着循环,逐个尝试,逐个更新。 (j=0(1元),dp【1】=min(dp【1】,dp【1-arr【0】】+1))
(j=1(2元),dp【1】=min(dp【1】,dp【1-arr【1】】+1))
//但是当然只有面值不超过要凑的钱才能用 (j=2(5元),dp【1】=min(dp【1】,dp【1-arr【2】】+1))
//如果面值不超过要凑的钱才能用
if(arr[j] <= i) //由于加了if条件,就相当于排除了i - arr[j] 的部分,
//维护最小值
dp[i] = min(dp[i], dp[i - arr[j]] + 1); //对于任意来的i,用第一个钱币的起始值为aim ,然后满足条件逐步更新,确定是要维持当前的dp【i】值还是选择dp[i - arr[j]] 的值多一种作为新的dp【i】
}
}
//如果最终答案大于aim代表无解
returndp[aim] > aim ? -1: dp[aim];
}
};