CC88 不同路径的数目(一)
题目描述
一个机器人在m×n大小的地图的左上角(起点)。机器人每次可以向下或向右移动。机器人要到达地图的右下角(终点)。可以有多少种不同的路径从起点走到终点?
解题思路
- 状态F(i, j) : 从(0, 0)到(i, j)的路径个数
- 状态转移方程 : F(i-1, j) + F(i, j-1)
- 初始状态 : F(i, 0) = F(0, j) = 1
- 返回 : F(row-1, col-1)
class Solution {
public:
/**
*
* @param m int整型
* @param n int整型
* @return int整型
*/
int uniquePaths(int m, int n) {
// write code here
vector<vector<int>> ret(m, vector<int>(n, 1));//m-row,n-col
//初始条件 第一行 = 第一列 = 1
for(int i = 0; i < m; ++i)
ret[i][0] = 1;
for(int i = 0; i < n; ++i)
ret[0][i] = 1;
//状态转移方程
for(int i = 1; i < m; i++)
{
for(int j = 1; j < n; j++)
{
ret[i][j] = ret[i][j-1] + ret[i-1][j];
}
}
return ret[m-1][n-1];
}
};
CC86 带权值的最小路径和
题目描述
给定一个由非负整数填充的m x n的二维数组,现在要从二维数组的左上角走到右下角,请找出路径上的所有数字之和最小的路径。注意:你每次只能向下或向右移动。
解题思路
- 状态F(i, j) : 从(0, 0)到(i, j)的最短路径和
- 状态转移方程 :
min(F(i-1, j) + F(i, j-1)) + array[i][j]
- 初始状态 :
F(0, 0) = array[0][0]
F(i, 0) = F(i-1, 0) + array[i][0]
F(0, j) = F(0, j-1) + array[0][j]
- 返回 : F(row-1, col-1)
class Solution {
public:
/**
*
* @param grid int整型vector<vector<>>
* @return int整型
*/
int minPathSum(vector<vector<int> >& grid) {
// write code here
vector<vector<int>> ret(grid);
int row = grid.size();
int col = grid[0].size();
//初始条件
for(int i = 1; i < row; i++)
ret[i][0] = ret[i-1][0] + grid[i][0];
for(int i = 1; i < col; i++)
ret[0][i] = ret[0][i-1] + grid[0][i];
//转移方程
for(int i = 1; i < row; ++i)
{
for(int j = 1; j < col; ++j)
{
ret[i][j] = min(ret[i-1][j], ret[i][j-1]) + grid[i][j];
}
}【
return ret[row-1][col-1];
}
};
背包问题(0,1背包)
问题描述
有 n 个物品和一个大小为 m 的背包. 给定数组 A 表示每个物品的大小和数组 V 表示每个物品的价值。问最多能装入背包的总价值是多大?
解题思路
状态范围索引是从1开始,价值数组和大小数组索引范围是从0开始,故第i个商品的容量为A[i-1],价值为V[i-1]
这里就要用到二维数组来表示价值和容量的关系。
情况1:放入第i个商品但是要取出某个商品 F(i, j) = F(i-1, j - A[i-1]) + V[i],j-A[i-1]表示容量要扣除掉第i个商品的体积【是第2种情况的子情况,因为对于背包的容量来说情况1和2都没超重】;
情况2:放入第i个商品 F(i, j) = F(i-1, j) + V[i]
情况3:不放入第i个商品,F(i, j) = F(i-1, j)【第i个商品放不下的时候,就会直接退化到上一个商品的状态值】
状态描述F(i, j) : 表示把第i个物品放入容量为j的背包中,此时该背包价值最大。
状态转移方程:如果A[i-1] > j ,表示情况3不放入第i个商品,F(i, j) = F(i-1, j);如果A[i-1] <= j,表示情况1和2放入第i个商品,F(i, j) = max(F(i-1, j), F(i-1, j - A[i-1]) + V[i-1]);
初始值:F(0, j) = 0 表示包有足够的容量,但是没有放入任何商品,价值为0;F(i, 0) = 0表示包容量为0,故价值为0
返回 : F(n, m)
class Solution {
public:
/**
* @param m: An integer m denotes the size of a backpack
* @param A: Given n items with size A[i]
* @param V: Given n items with value V[i]
* @return: The maximum value
*/
int backPackII(int m, vector<int> A, vector<int> V) {
//若无商品或者无背包,则直接返回0
if(A.empty() || V.empty() || m < 1)
return 0;
//多加一行一列,给初始条件赋值
const int N = A.size() + 1;//物品个数
const int M = m + 1;//背包数
//初始条件 F(i, 0) = F(0, j) = 0
vector<vector<int>> ret(N, vector<int>(M, 0));
//状态递推
for(int i = 1; i < N; ++i)
{
for(int j = 1; j < M; ++j)
{
//第i个商品在A中对应的索引为i-1: i从1开始
//如果第i个商品大于j,说明放不下, 所以(i,j)的最大价值和(i-1,j)相同
if(A[i-1] > j) ret[i][j] = ret[i-1][j];
else
ret[i][j] = max(ret[i-1][j], ret[i-1][j-A[i-1]] + V[i-1]);
}
}
return ret[N-1][m];
}
};
//用一维数组实现,内内层循环要从后往前更新
const int N = A.size();//物品个数
const int M = m + 1;//背包数
vector<int> ret(M, 0);
for(int i = 1; i <= N; ++i)
{
for(int j = M - 1; j > 0; --j)
{
if(A[i] <= j) ret[j] = max(ret[j], ret[j-A[i]] + V[i]);
else ret[j] = ret[j];
}
}
return ret[m];