动态规划学习一
动态规划,虽然抽象后进行求解的思路并不复杂,但具体的形式千差万别,找出问题的子结构以及通过子结构重新构造最优解的过程很难统一.
动态规划求解的一般思路
判断问题的子结构,也可以看做状态,当具有最优子结构时,动态规划可能适用.
求解重叠子问题.一个递归算法不断地调用调用同一个问题,递归UI可以转化为查表从而利用子问题的解.
分治法则不同,每次递归都产生新的问题,重新构造一个最优解.
备忘录法,是动态规划的一种变形,自顶向下的策略.更像递归算法,初始化表为一个特殊值,标记未填充,当递归算法第一次遇到子问题,计算并填表.而后每次遇到只需要直接从表中取值.
1 硬币找零问题
假设有几种硬币,如1,3,5并且数量无限.
请找出能够组成某个数目的找零所使用使用的最小硬币数
解法:
-
假设硬币的种类由 coin[0…n-1] 数组表示.
-
用待找零的数目k 描述 子结构/状态. 记作 sum[k]. 表示找零k所需的最小硬币数.
-
最终需要求解的是 sum[total].
-
那么递归公式有
sum[k] = min(sum[k-coin[0],sum[k-con[1]…sum[k-coin[n-1])+1.
状态表示:
typdef struct{
int nCoin; // 使用硬币数量
// 以下两个成员为了便于构造出求解过程的展示
int lastSum; // 上一个状态
int addCoin; // 从上一个状态达到当前状态所需要的是哪种硬币
} state;
// 求解过程
state *sum = malloc(sizeof(state)*(total+1));
//init
for(i=0;i<=total;i++)
sum[i].nCoin = INF;
sum[0].nCoin = 0;
sum[0].lastSum = 0;
for(int i=1;i<=total;i++){
for(int j=0;j<n;j++){
if(i-coin[j]>=0&&sum[i-coin[j]].nCoin+1<sum[i].nCoin){
sum[i].nCoin = sum[i-coin[j]].nCoin+1;
sum[i].lastSum=j;
sum[i].addCoin=coin[j];
}
}
}
if(sum[total].nCoin==INF){
printf("can't make change.\n");
return -1;
}
else{
return sum[total].nCoin;
}
LeetCode 322. Coin Change
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
// 将所需数量标记为最大
vector<int> dp(amount + 1, INT_MAX);
dp[0] = 0;// 总数为0,无需硬币
for (int i = 1; i < amount + 1; ++i) {
for (int j = 0; j < coins.size(); ++j) {
if (i - coins[j] >= 0 && dp[i - coins[j]] < dp[i]/*注意是小于号*/) {
dp[i] = dp[i - coins[j]] + 1;
}
}
}
if (dp[amount] == INT_MAX) {
return -1;
} else {
return dp[amount];
}
}
};
扩展
一个矩形区域被划分为N*M的小矩形格子,在格子(i,j)中有A[i,j]个苹果.
现在从左上角的格子(1,1)出发,要求每次只能向右走一步或向下走一步,最后到达(N,M),每经过一个格子就把其中的苹果全部拿走.
请找出能拿到最多(或最少)苹果数的路线.
LeetCode 64. Minimum Path Sum
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if (grid.empty())
return 0;
int rows = grid.size();
int cols = grid[0].size();
// 第一行
for (int i = 1; i < cols; ++i) {
grid[0][i] += grid[0][i - 1];
}
// 第一列
for (int i = 1; i < rows; ++i) {
grid[i][0] += grid[i - 1][0];
}
// 累加
for (int i = 1; i < rows; ++i) {
for (int j = 1; j < cols; ++j) {
grid[i][j] += min(grid[i - 1][j], grid[i][j - 1]);
}
}
return grid[rows - 1][cols - 1];
}
};
LeetCode 741. herry Pickup
这个题有点难.待补充