【动态规划】讲解

动态规划(Dynamic Programming)是一种解决复杂问题的算法思想。它的核心思想是将原问题分解为一系列子问题,并保存子问题的解,以避免重复计算,从而提高算法的效率。在C++中,可以通过递归和动态规划的组合来解决一些具有重叠子问题的问题。
动态规划的解决思路通常包括以下几个步骤:

  1.  定义状态:将问题抽象成一个数学模型,明确问题的状态和状态之间的关系。状态通常是问题中需要保存的信息,可以是一个变量或者一个数组。
  2. 定义状态转移方程:找出问题的状态转移方程,即当前状态和之前状态之间的关系。通过递归或迭代的方式,将问题划分为更小的子问题,并通过状态转移方程求解子问题。        
  3. 确定初始条件:确定初始状态的值,即边界条件。初始条件通常是原问题中的基本情况,例如最小规模的子问题。
  4. 通过迭代求解:通过不断迭代和计算子问题的解,得到原问题的解。通常使用循环结构来实现迭代。

在C++中,可以使用动态规划来解决各种问题,包括最长递增子序列、背包问题、最短路径、最大子数组和等等。下面将分别介绍这些问题并给出相应的C++代码。1. 最长递增子序列(Longest Increasing Subsequence)
最长递增子序列指的是在给定序列中找到一个最长的子序列,使得子序列中的元素按升序排列。这个问题可以通过动态规划的方法求解。具体代码如下:

#include <iostream>
#include <vector>
using namespace std;

int longestIncreasingSubsequence(vector<int>& nums) {
    int n = nums.size();
    vector<int> dp(n, 1);
    int maxLength = 1;
    
    for (int i = 1; i < n; i++) {
        for (int j = 0; j < i; j++) {
            if (nums[i] > nums[j]) {
                dp[i] = max(dp[i], dp[j] + 1);
            }
        }
        maxLength = max(maxLength, dp[i]);
    }
    
    return maxLength;
}

int main() {
    vector<int> nums = {10, 9, 2, 5, 3, 7, 101, 18};
    int result = longestIncreasingSubsequence(nums);
    cout << "Length of longest increasing subsequence: " << result << endl;
    
    return 0;
}

2. 背包问题(Knapsack Problem)
背包问题是指在给定的一组物品中,选择一些物品放入一个背包中,使得物品的总价值最大,但不能超过背包的容量。这个问题可以通过动态规划的方法求解。具体代码如下:
 

#include <iostream>
#include <vector>
using namespace std;

int knapsack(vector<int>& values, vector<int>& weights, int capacity) {
    int n = values.size();
    vector<vector<int>> dp(n + 1, vector<int>(capacity + 1, 0));
    
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= capacity; j++) {
            if (weights[i - 1] <= j) {
                dp[i][j] = 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][capacity];
}

int main() {
    vector<int> values = {60, 100, 120};
    vector<int> weights = {10, 20, 30};
    int capacity = 50;
    int result = knapsack(values, weights, capacity);
    cout << "Maximum value: " << result << endl;
    
    return 0;
}

3. 最短路径(Shortest Path)
最短路径问题是指在一个加权有向图中,求解两个顶点之间的最短路径。这个问题可以通过动态规划的方法求解。具体代码如下:

#include <iostream>
#include <vector>
#include <climits>
using namespace std;
int shortestPath(vector<vector<int>>& graph, int source, int target) {
    int n = graph.size();
    vector<int> dist(n, INT_MAX);
    dist[source] = 0;
    
    for (int k = 1; k < n; k++) {
        for (int u = 0; u < n; u++) {
            for (int v = 0; v < n; v++) {
                if (graph[u][v] != INT_MAX && dist[u] != INT_MAX && dist[u] + graph[u][v] < dist[v]) {
                    dist[v] = dist[u] + graph[u][v];
                }
            }
        }
    }
    
    return dist[target];
}
int main() {
    vector<vector<int>> graph = {{0, 5, INT_MAX, 10},
                                 {INT_MAX, 0, 3, INT_MAX},
                                 {INT_MAX, INT_MAX, 0, 1},
                                 {INT_MAX, INT_MAX, INT_MAX, 0}};
    int source = 0;
    int target = 3;
    int result = shortestPath(graph, source, target);
    cout << "Shortest path length: " << result << endl;
    
    return 0;
}

4. 最大子数组和(Maximum Subarray Sum)
最大子数组和问题是指在一个给定的整数数组中,找到一个具有最大和的连续子数组。这个问题可以通过动态规划的方法求解。具体代码如下:

#include <iostream>
#include <vector>
#include <climits>
using namespace std;
int maximumSubarraySum(vector<int>& nums) {
    int n = nums.size();
    vector<int> dp(n, 0);
    dp[0] = nums[0];
    int maxSum = nums[0];
    
    for (int i = 1; i < n; i++) {
        dp[i] = max(nums[i], dp[i - 1] + nums[i]);
        maxSum = max(maxSum, dp[i]);
    }
    
    return maxSum;
}
int main() {
    vector<int> nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4};
    int result = maximumSubarraySum(nums);
    cout << "Maximum subarray sum: " << result << endl;
    
    return 0;
}

以上只是动态规划的一些示例,动态规划还可以应用于更多的问题。通过合理的子问题设置和状态转移方程,可以解决许多实际问题。

点个赞吧,帅哥美女们,本人为小学生。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值