求最值型动态规划
持续更新中、、、
基本套路
一、确定状态
最后一步
转换为子问题(子问题最优,总问题也最优)
二、转移方程
f[x] = min{dfjakfadkjf,dfjkajdkl ,jklajdflka}
三、初始条件和边界情况
f[0] = 0
如果不能,,,就、、、、、
四、计算顺序
自底向上,,将所有的值都求出来,f[0],f[1],f[M],然后从中选取最大值
递归是自顶向下,,,有很多重复,,
动态规划使用数组记录中间结果,简称备忘录,,然后这样就能避免重复计算
例题一
public class Solution {
/**
* @param coins: a list of integer
* @param amount: a total amount of money amount
* @return: the fewest number of coins that you need to make up
*/
public int coinChange(int[] coins, int amount) {
int n = coins.length;
int[] f = new int[amount+1]; //记录f[0]---f[amount]
int i, j;
//initialize
f[0] = 0;
for(i=1; i<=amount; ++i){
f[i] = Integer.MAX_VALUE; //initialize to Infinity
for(j=0; j<n; ++j){
if(i>=coins[j] && f[i-coins[j]]!=Integer.MAX_VALUE && f[i-coins[j]]+1<f[i]){
f[i] = f[i-coins[j]]+1;
}
}
}
if(f[amount]==Integer.MAX_VALUE){
return -1;
}else{
return f[amount];
}
}
}
关于那三个条件的解释:
更新f[i]的三大条件:::
(1) 最后一枚硬币不能大于当前面值A[j]
(2) 子问题本身不能是拼不出来的
f[i-A[j]] != 无穷
(3)如果子问题能拼出来,那么它用的硬币数+1,要小于原问题是才更新!
这个题目的递归解法
例题二 poj3616
#include <iostream>
#include <algorithm>
using namespace std;
int f[1050];
struct FJ{
int start;
int end;
int efficency;
}interval[1050];
int cmp(const FJ a, const FJ b){
if(a.start==b.start)
return a.end<b.end;
return a.start<b.start;
}
int main(){
int n,m,r;
int i,j;
scanf("%d%d%d",&n,&m,&r);
for(i=0; i<m; i++){
scanf("%d%d%d",&interval[i].start,&interval[i].end,&interval[i].efficency);
interval[i].end += r;
}
// f[0]=0;
sort(interval,interval+m,cmp);
for(i=0; i<m; ++i){
f[i] = interval[i].efficency;
for(j=0; j<i; ++j){
if(interval[j].end<=interval[i].start){
f[i] = max(f[i],f[j] + interval[i].efficency);
}
}
}
cout << *max_element(f, f + m) << endl;
// cout<<f[m-1]<<endl;
}
这个题目带给我的体会是,最后那个f[m-1]不一定是最大值,得到的数组f[]不一定是递增的,,最后使用max_element函数求第一个最大值——————》为了避免重复出现最大值的情况