动态规划(Dynamic Programming, DP)是一种用于解决最优化问题的算法设计方法。它通过将大问题分解为小问题来避免重复计算,通常适用于具有重叠子问题和最优子结构性质的问题。
动态规划的基本步骤
- 定义状态:确定问题的状态以及如何用状态表示问题的解。
- 选择决策:找出状态转移的方式,也就是如何通过选择决策来转移到下一个状态。
- 写出状态转移方程:根据决策和状态之间的关系,构建转移方程。
- 确定边界条件:设定初始状态的值。
- 实现并求解:通过迭代或递归计算最终解。
例子:斐波那契数列
一个经典的动态规划问题是求斐波那契数列的第 n
项。
状态定义
f(n)
表示第 n
项的值。
状态转移方程
f(n) = f(n-1) + f(n-2)
边界条件
f(0) = 0
f(1) = 1
示例代码
#include <iostream>
#include <vector>
int fibonacci(int n) {
// 边界条件
if (n <= 1) return n;
// 创建一个数组来存储斐波那契数列
std::vector<int> dp(n + 1);
dp[0] = 0; // f(0)
dp[1] = 1; // f(1)
// 填充动态规划表
for (int i = 2; i <= n; ++i) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n]; // 返回 f(n)
}
int main() {
int n;
std::cout << "Enter a number: ";
std::cin >> n;
int result = fibonacci(n);
std::cout << "Fibonacci number at position " << n << " is: " << result << std::endl;
return 0;
}
运行说明
- 输入一个非负整数
n
。 - 程序输出斐波那契数列中第
n
项的值。
例子:01背包
问题描述
- 有
n
件物品,每件物品的重量为weights[i]
,价值为values[i]
。 - 背包的最大承重为
W
。 - 目标是选择物品,使得在不超过承重的前提下,最大化总价值。
动态规划解法
状态定义
dp[i][j]
表示前 i
件物品在最大承重为 j
的情况下的最大价值。
状态转移方程
- 如果不选择第
i
件物品:dp[i][j] = dp[i-1][j]
- 如果选择第
i
件物品:dp[i][j] = dp[i-1][j-weights[i-1]] + values[i-1]
- 综合:
dp[i][j] = max(dp[i-1][j], dp[i-1][j-weights[i-1]] + values[i-1])
(前提是j >= weights[i-1]
)
边界条件
dp[0][j] = 0
(没有物品时的最大价值为 0)
示例代码
#include <iostream>
#include <vector>
#include <algorithm>
int knapsack(int W, const std::vector<int>& weights, const std::vector<int>& values) {
int n = weights.size();
// 创建 DP 表
std::vector<std::vector<int>> dp(n + 1, std::vector<int>(W + 1, 0));
// 填充 DP 表
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= W; ++j) {
if (weights[i - 1] <= j) {
dp[i][j] = std::max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + values[i - 1]);
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
return dp[n][W]; // 返回最大价值
}
int main() {
int W; // 背包容量
std::cout << "Enter the maximum weight of the knapsack: ";
std::cin >> W;
int n; // 物品数量
std::cout << "Enter the number of items: ";
std::cin >> n;
std::vector<int> weights(n);
std::vector<int> values(n);
std::cout << "Enter weights of items: ";
for (int i = 0; i < n; ++i) {
std::cin >> weights[i];
}
std::cout << "Enter values of items: ";
for (int i = 0; i < n; ++i) {
std::cin >> values[i];
}
int max_value = knapsack(W, weights, values);
std::cout << "Maximum value in the knapsack: " << max_value << std::endl;
return 0;
}
运行说明
- 输入背包的最大承重
W
。 - 输入物品数量
n
。 - 输入每件物品的重量和价值。
- 程序输出在给定条件下的最大价值。