动态规划问题递推公式大全(也叫状态转移方程,可直接查阅,持续更新)

动态规划问题通过直接思考并编程解决问题是很难的,而且十分费时间,所以我整理了一份动态规划递推公式大全,可用于直接查阅并直接套用进行编程,同时附加上完整代码,文章将分为一维和多维进行总结。

一维动态规划

1.斐波那契数列/爬楼梯

递推公式:dp[i] = dp[i-1] + dp[i-2]

初始化:

dp[0] = 1(地面算1种方式)

dp[1] = 1(爬1阶只有1种方式)

2.打家劫舍系列

基础版(无环)

递推公式:dp[i] = max(dp[i-1], dp[i-2] + nums[i])

初始化:

dp[0] = nums[0]

dp[1] = max(nums[0], nums[1])

环形版

拆分为两个子问题:

不抢第一间:robRange(nums, 1, n-1)

不抢最后一间:robRange(nums, 0, n-2)

初始化:与基础版相同,但处理不同区间。

代码(递推公式有点特殊,需要示例代码才能说清楚):

int rob(vector& nums) {
    int n = nums.size();
    if (n == 0) return 0;
    if (n == 1) return nums[0];
    return max(robRange(nums, 0, n-2), robRange(nums, 1, n-1));
}

int robRange(vector& nums, int start, int end) {
    if (start > end) return 0;
    int prev1 = 0, prev2 = 0;
    for (int i = start; i <= end; i++) {
        int curr = max(prev1, prev2 + nums[i]);
        prev2 = prev1;
        prev1 = curr;
    }
    return prev1;
}

树形版

递推公式:

后序遍历返回 [抢当前节点的收益, 不抢的收益]

抢当前节点:rob_val = node->val + left[1] + right[1]

不抢当前节点:not_rob_val = max(left[0], left[1]) + max(right[0], right[1])

初始化:空节点返回 {0, 0}

代码(递推公式有点特殊,需要示例代码才能说清楚):

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

pair dfs(TreeNode* node) {
    if (!node) return {0, 0};
    auto left = dfs(node->left);
    auto right = dfs(node->right);
    int rob_val = node->val + left.second + right.second;
    int not_rob_val = max(left.first, left.second) + max(right.first, right.second);
    return {rob_val, not_rob_val};
}

int rob(TreeNode* root) {
    auto res = dfs(root);
    return max(res.first, res.second);
}

3.最长递增子序列(LIS)

递推公式:dp[i] = max(dp[j] + 1)(对所有 j < i 且 nums[j] < nums[i])

初始化:dp 数组全初始化为 1

完整示例代码:

#include 
#include 
#include 

using namespace std;

int lengthOfLIS(vector& nums) {
    if (nums.empty()) return 0;

    int n = nums.size();
    // 初始化 dp 数组,每个元素的最长递增子序列初始为 1
    vector dp(n, 1);

    // 动态规划计算 dp 数组
    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);
            }
        }
    }

    // 最长递增子序列的长度是 dp 数组中的最大值
    return *max_element(dp.begin(), dp.end());
}

4.最大子数组和

递推公式:dp[i] = max(nums[i], dp[i-1] + nums[i])

初始化:dp[0] = nums[0]

完整示例代码:

#include 
#include 
#include 

using namespace std;

int maxSubArray(vector& nums) {
    if (nums.empty()) return 0;

    int n = nums.size();
    // 初始化 dp 数组,dp[i]表示以 nums[i] 结尾的最大子数组和
    vector dp(n);
    dp[0] = nums[0];  // 初始化 dp[0] 为 nums[0]

    // 动态规划计算 dp 数组
    for (int i = 1; i < n; ++i) {
        dp[i] = max(nums[i], dp[i-1] + nums[i]);
    }

    // 返回 dp 数组中的最大值,即为最大子数组和
    return *max_element(dp.begin(), dp.end());
}

5.零钱兑换(Coin Change)

变体1:最小硬币数

递推公式:dp[i] = min(dp[i], dp[i - coin] + 1)  # 对所有硬币面额 coin <= i

初始化:dp[0] = 0,其他为正无穷。

说明:用最少数量的硬币凑出金额 amount,外层遍历金额,内层遍历硬币(顺序无关)。

完整示例代码:

#include 
#include 
#include 

using namespace std;

int coinChange(vector& coins, int amount) {
    // 初始化 dp 数组,dp[i] 表示凑成金额 i 的最小硬币数
    vector dp(amount + 1, amount + 1); // 用一个大数表示正无穷
    dp[0] = 0;  // 需要 0 个硬币来凑成 0 元

    // 外层遍历金额
    for (int i = 1; i <= amount; ++i) {
        // 内层遍历硬币
        for (int coin : coins) {
            if (i - coin >= 0) {
                dp[i] = min(dp[i], dp[i - coin] + 1);  // 更新 dp[i]
            }
        }
    }

    // 如果 dp[amount] 仍然是正无穷,说明无法凑成 amount
    return dp[amount] > amount ? -1 : dp[amount];
}

int main() {
    vector coins = {1, 2, 5}; // 可用的硬币面额
    int amount = 11;  // 要凑成的金额
    cout << "Minimum coins required: " << coinChange(coins, amount) << endl;
    return 0;
}

变体2:组合数

递推公式:dp[i] += dp[i - coin]  # 对所有硬币面额 coin <= i

初始化:dp[0] = 1(空组合)。

说明:计算凑出金额 amount 的硬币组合数(顺序不同视为相同),外层遍历硬币 coin,内层遍历金额 i(避免重复计数顺序)。

完整示例代码:

#include 
#include 
#include 

using namespace std;

int coinChangeCombinations(vector& coins, int amount) {
    // 初始化 dp 数组,dp[i] 表示凑成金额 i 的硬币组合数
    vector dp(amount + 1, 0);
    dp[0] = 1;  // 需要 1 种方式凑成 0 元(空组合)

    // 外层遍历硬币
    for (int coin : coins) {
        // 内层遍历金额,从 coin 到 amount,避免重复计数顺序
        for (int i = coin; i <= amount; ++i) {
            dp[i] += dp[i - coin];  // 更新 dp[i]
        }
    }

    // 返回凑成金额 amount 的硬币组合数
    return dp[amount];
}

int main() {
    vector coins = {1, 2, 5}; // 可用的硬币面额
    int amount = 5;  // 要凑成的金额
    cout << "Number of combinations: " << coinChangeCombinations(coins, amount) << endl;
    return 0;
}

变体3:排列数

递推公式:dp[i] += dp[i - coin]  # 对所有硬币面额 coin <= i

初始化:dp[0] = 1(空组合)。

说明:计算凑出金额 amount 的硬币排列数(顺序不同视为不同方案),外层遍历金额 i,内层遍历硬币 coin(允许不同顺序组合)。

完整示例代码:

#include 
#include 
#include 

using namespace std;

int coinChangePermutations(vector& coins, int amount) {
    // 初始化 dp 数组,dp[i] 表示凑成金额 i 的硬币排列数
    vector dp(amount + 1, 0);
    dp[0] = 1;  // 需要 1 种方式凑成 0 元(空组合)

    // 外层遍历金额 i
    for (int i = 1; i <= amount; ++i) {
        // 内层遍历硬币,允许不同顺序组合
        for (int coin : coins) {
            if (i - coin >= 0) {
                dp[i] += dp[i - coin];  // 更新 dp[i],加入当前硬币的排列数
            }
        }
    }

    // 返回凑成金额 amount 的硬币排列数
    return dp[amount];
}

int main() {
    vector coins = {1, 2, 5}; // 可用的硬币面额
    int amount = 5;  // 要凑成的金额
    cout << "Number of permutations: " << coinChangePermutations(coins, amount) << endl;
    return 0;
}

维动态规划(矩阵或双序列问题)

1. 背包问题

0-1背包(物品不可重复,只有一件)

// 初始化
vector> dp(n+1, vector(capacity+1, 0));

// 递推公式
if (j >= w[i-1]) {
   dp[i][j] = max(dp[i-1][j], dp[i-1][j - w[i-1]] + v[i-1]);
 } else {
   dp[i][j] = dp[i-1][j];
 }


// 返回值
return dp[n][capacity];

 完整示例代码:
 

#include 
#include 
#include 
using namespace std;

int knapsack_2d(vector& weights, vector& values, int capacity) {
    int n = weights.size();
    vector> dp(n + 1, vector(capacity + 1, 0));
    
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= capacity; j++) {
            if (j >= weights[i-1]) {
                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 weights = {2, 3, 4, 5};  // 物品重量
    vector values = {3, 4, 5, 6};   // 物品价值
    int capacity = 8;                     // 背包容量
    
    cout << "Maximum value (2D DP): " 
         << knapsack_2d(weights, values, capacity) << endl;
    // 输出: 10 (选物品1和物品3,重量3+5=8,价值4+6=10)
    return 0;
}

完全背包(每种物品数量无限)

// 初始化(同0-1背包)
vector> dp(n+1, vector(capacity+1, 0));

// 递推公式
if (j >= weights[i-1]) {
      dp[i][j] = max(dp[i-1][j], dp[i][j - weights[i-1]] + values[i-1]);  // 关键区别
 } else {
      dp[i][j] = dp[i-1][j];
 }


// 返回值
return dp[n][capacity];

完整示例代码:

#include 
#include 
#include 
using namespace std;

int unboundedKnapsack_2d(vector& weights, vector& values, int capacity) {
    int n = weights.size();
    vector> dp(n + 1, vector(capacity + 1, 0));
    
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= capacity; j++) {
            if (j >= weights[i-1]) {
                dp[i][j] = max(dp[i-1][j], dp[i][j - weights[i-1]] + values[i-1]);  // 关键区别
            } else {
                dp[i][j] = dp[i-1][j];
            }
        }
    }
    return dp[n][capacity];
}

多重背包(每种物品有一定数量)

// 初始化
vector dp(capacity+1, 0);

// 递推公式
dp[j] = max(dp[j], dp[j - k * weights[i]] + k * values[i]);


// 返回值
return dp[capacity];

 完整示例代码:

#include 
#include 
#include 
using namespace std;

int multiKnapsack_plain(vector& weights, vector& values, vector& counts, int capacity) {
    vector dp(capacity + 1, 0);
    
    for (int i = 0; i < weights.size(); i++) {
        for (int j = capacity; j >= weights[i]; j--) {  // 逆序
            for (int k = 1; k <= counts[i] && k * weights[i] <= j; k++) {
                dp[j] = max(dp[j], dp[j - k * weights[i]] + k * values[i]);
            }
        }
    }
    return dp[capacity];
}

int main() {
    vector weights = {1, 2, 3};    // 物品重量
    vector values = {6, 10, 12};   // 物品价值
    vector counts = {2, 3, 2};     // 物品数量限制
    int capacity = 5;                   // 背包容量
    
    cout << "Maximum value (plain): " 
         << multiKnapsack_plain(weights, values, counts, capacity) << endl;
    // 输出: 22 (选2个物品0和1个物品1: 2*1 + 1*2 ≤5, 2*6 + 1*10=22)
    return 0;
}

2. 股票交易系列

问题类型:在股票买卖限制下获取最大利润

基础版(一次交易)

// 初始化
vector> dp(n, vector(2, 0));
dp[0][1] = -prices[0];


// 递推公式
dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
dp[i][1] = max(dp[i-1][1], -prices[i])


// 返回值
return dp[n-1][0];

完整示例代码:

int maxProfit_dp(vector& prices) {
    int n = prices.size();
    if (n == 0) return 0;
    
    // dp[i][0]: 第i天不持有股票的最大利润
    // dp[i][1]: 第i天持有股票的最大利润
    vector> dp(n, vector(2, 0));
    dp[0][1] = -prices[0]; // 第一天买入
    
    for (int i = 1; i < n; i++) {
        dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i]); // 卖出或保持不持有
        dp[i][1] = max(dp[i-1][1], -prices[i]);             // 买入或保持持有(只能买一次)
    }
    
    return dp[n-1][0]; // 最后一天不持有股票
}

无限次交易

// 递推公式
dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])

// 初始化(同基础版)

// 返回值
return dp[n-1][0];

完整示例代码:

#include 
#include 
using namespace std;

int maxProfit(vector& prices) {
    int n = prices.size();
    if (n == 0) return 0;

    // dp[i][0]: 第i天不持股;dp[i][1]: 第i天持股
    vector> dp(n, vector(2));

    // 初始化第一天
    dp[0][0] = 0;            // 不持股收益为0
    dp[0][1] = -prices[0];   // 持股收益为负,因为买入花钱了

    for (int i = 1; i < n; ++i) {
        // 今天不持股 = max(昨天不持股, 昨天持股今天卖出)
        dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i]);

        // 今天持股 = max(昨天持股, 昨天不持股今天买入)
        dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i]);
    }

    // 最后一天不持股时的利润最大
    return dp[n-1][0];
}

 限k次交易(属于难题,不用太管它)

一个完整的示例代码

#include 
#include 
#include 
using namespace std;

int maxProfit(int k, vector& prices) {
    int n = prices.size();
    if (n == 0 || k == 0) return 0;

    // 如果交易次数大于n/2,则相当于无限次交易
    if (k >= n / 2) {
        int profit = 0;
        for (int i = 1; i < n; ++i)
            if (prices[i] > prices[i - 1])
                profit += prices[i] - prices[i - 1];
        return profit;
    }

    // 定义三维DP数组:天数 × 最大交易次数 + 1 × 持股状态(0/1)
    vector>> dp(n, vector>(k + 1, vector(2, 0)));

    // 初始化:第0天持股状态
    for (int j = 0; j <= k; ++j) {
        dp[0][j][0] = 0;
        dp[0][j][1] = -prices[0];  // 花钱买入
    }

    for (int i = 1; i < n; ++i) {
        for (int j = 1; j <= k; ++j) {
            // 不持股:昨天就不持股 or 昨天持股今天卖出
            dp[i][j][0] = max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i]);

            // 持股:昨天就持股 or 昨天没持股今天买入(消耗一次交易)
            dp[i][j][1] = max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i]);
        }
    }

    return dp[n - 1][k][0];  // 最后一天不能持股
}

3. 双序列问题

问题类型:处理两个序列的匹配/比较问题

最长公共子序列(LCS)

// 初始化
vector> dp(m+1, vector(n+1, 0));

// 递推公式
if(s1[i-1] == s2[j-1])
    dp[i][j] = dp[i-1][j-1] + 1
else
    dp[i][j] = max(dp[i-1][j], dp[i][j-1])


// 返回值
return dp[m][n];

一个完整的示例代码:

#include 
#include 
#include 
using namespace std;

int longestCommonSubsequence(string text1, string text2) {
    int m = text1.length(), n = text2.length();

    // dp[i][j] 表示 text1[0..i-1] 和 text2[0..j-1] 的 LCS 长度
    vector> dp(m + 1, vector(n + 1, 0));

    // 遍历所有字符
    for (int i = 1; i <= m; ++i) {
        for (int j = 1; j <= n; ++j) {
            if (text1[i - 1] == text2[j - 1]) {
                // 字符相同,LCS长度加1
                dp[i][j] = dp[i - 1][j - 1] + 1;
            } else {
                // 字符不同,取前一个状态的最大值
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }

    return dp[m][n];
}

编辑距离

// 初始化
vector> dp(m+1, vector(n+1, 0));
for(int i=1; i<=m; i++) dp[i][0] = i;
for(int j=1; j<=n; j++) dp[0][j] = j;


// 递推公式
if(s1[i-1] == s2[j-1])
    dp[i][j] = dp[i-1][j-1]
else
    dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])


// 返回值
return dp[m][n];

 一个完整的示例代码:

#include 
#include 
#include 
using namespace std;

int minDistance(string word1, string word2) {
    int m = word1.length(), n = word2.length();
    
    // 创建DP表,表示 word1[0..i-1] 转为 word2[0..j-1] 的最少编辑操作
    vector> dp(m + 1, vector(n + 1, 0));
    
    // 初始化边界条件
    for (int i = 0; i <= m; ++i) dp[i][0] = i; // 删除所有字符
    for (int j = 0; j <= n; ++j) dp[0][j] = j; // 插入所有字符

    // 填表
    for (int i = 1; i <= m; ++i) {
        for (int j = 1; j <= n; ++j) {
            if (word1[i - 1] == word2[j - 1]) {
                // 字符相同,不需要操作
                dp[i][j] = dp[i - 1][j - 1];
            } else {
                // 三种操作取最小 +1
                dp[i][j] = 1 + min({
                    dp[i - 1][j],     // 删除
                    dp[i][j - 1],     // 插入
                    dp[i - 1][j - 1]  // 替换
                });
            }
        }
    }

    return dp[m][n];
}

4. 矩阵路径问题

问题类型:在矩阵中寻找最优路径

最小路径和

// 初始化
vector> dp(m, vector(n, 0));
dp[0][0] = grid[0][0];
for(int i=1; i

  一个完整的示例代码:

#include 
#include 
using namespace std;

int minPathSum(vector>& grid) {
    int m = grid.size();
    int n = grid[0].size();

    // dp[i][j] 表示从 (0,0) 到 (i,j) 的最小路径和
    vector> dp(m, vector(n, 0));

    // 初始化起点
    dp[0][0] = grid[0][0];

    // 初始化第一列(只能从上往下走)
    for (int i = 1; i < m; ++i)
        dp[i][0] = dp[i - 1][0] + grid[i][0];

    // 初始化第一行(只能从左往右走)
    for (int j = 1; j < n; ++j)
        dp[0][j] = dp[0][j - 1] + grid[0][j];

    // 填充整个DP表
    for (int i = 1; i < m; ++i) {
        for (int j = 1; j < n; ++j) {
            // 取从上方或左方来的最小路径和
            dp[i][j] = grid[i][j] + min(dp[i - 1][j], dp[i][j - 1]);
        }
    }

    // 返回终点的最小路径和
    return dp[m - 1][n - 1];
}

不同路径总数(带障碍物)

// 初始化
vector> dp(m, vector(n, 0));
dp[0][0] = (grid[0][0] == 0) ? 1 : 0;


// 递推公式
if(grid[i][j] == 1)
    dp[i][j] = 0
else
    dp[i][j] = dp[i-1][j] + dp[i][j-1]


// 返回值
return dp[m-1][n-1];

  一个完整的示例代码:

#include 
using namespace std;

int uniquePathsWithObstacles(vector>& obstacleGrid) {
    int m = obstacleGrid.size();
    int n = obstacleGrid[0].size();

    vector> dp(m, vector(n, 0));

    // 初始化起点
    if (obstacleGrid[0][0] == 1)
        return 0;
    dp[0][0] = 1;

    // 初始化第一列
    for (int i = 1; i < m; ++i)
        dp[i][0] = (obstacleGrid[i][0] == 0 && dp[i - 1][0] == 1) ? 1 : 0;

    // 初始化第一行
    for (int j = 1; j < n; ++j)
        dp[0][j] = (obstacleGrid[0][j] == 0 && dp[0][j - 1] == 1) ? 1 : 0;

    // 填DP表
    for (int i = 1; i < m; ++i) {
        for (int j = 1; j < n; ++j) {
            if (obstacleGrid[i][j] == 0) {
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
            } else {
                dp[i][j] = 0; // 当前为障碍物
            }
        }
    }

    return dp[m - 1][n - 1];
}

5. 其他经典问题

正则表达式匹配

// 初始化
vector> dp(m+1, vector(n+1, false));
dp[0][0] = true;


// 递推公式
if(p[j-1] == '*')
    dp[i][j] = dp[i][j-2] || (s[i-1] == p[j-2] || p[j-2] == '.') && dp[i-1][j]
else
    dp[i][j] = (s[i-1] == p[j-1] || p[j-1] == '.') && dp[i-1][j-1]


// 返回值
return dp[m][n];

完整示例代码:

#include 
#include 
using namespace std;

bool isMatch(string s, string p) {
    int m = s.size();
    int n = p.size();

    // dp[i][j] 表示 s[0..i-1] 与 p[0..j-1] 是否匹配
    vector> dp(m + 1, vector(n + 1, false));
    dp[0][0] = true; // 空串与空串匹配

    // 初始化:s 是空串时,p 能否匹配空串
    for (int j = 2; j <= n; ++j) {
        if (p[j - 1] == '*')
            dp[0][j] = dp[0][j - 2];
    }

    // 填表
    for (int i = 1; i <= m; ++i) {
        for (int j = 1; j <= n; ++j) {
            if (p[j - 1] == '*') {
                // 匹配 0 次 p[j-2]
                dp[i][j] = dp[i][j - 2];
                // 匹配 >=1 次 p[j-2]
                if (s[i - 1] == p[j - 2] || p[j - 2] == '.') {
                    dp[i][j] |= dp[i - 1][j];
                }
            } else {
                // 直接匹配或通配符 '.'
                if (s[i - 1] == p[j - 1] || p[j - 1] == '.') {
                    dp[i][j] = dp[i - 1][j - 1];
                }
            }
        }
    }

    return dp[m][n];
}

石子游戏(博弈论)

说明:给定一个整数数组 piles,表示一排石子堆。两个玩家轮流从两端取一堆石子,取到的石子数量会累加为分数。假设两人都采用最优策略,判断先手是否一定能赢。

// 初始化
vector> dp(n, vector(n, 0));
for(int i=0; i 0;

 完整代码示例:

#include 
#include 
#include 
using namespace std;

bool stoneGame(vector& piles) {
    int n = piles.size();
    // dp[i][j] 表示从 piles[i..j] 区间中,当前玩家可以获得的最大净胜分
    vector> dp(n, vector(n, 0));

    // 初始化:只有一个石子时,当前玩家只能拿这个石子
    for (int i = 0; i < n; ++i) {
        dp[i][i] = piles[i];
    }

    // 枚举区间长度
    for (int len = 2; len <= n; ++len) {
        for (int i = 0; i + len - 1 < n; ++i) {
            int j = i + len - 1;
            // 当前玩家选择左或右,减去对方的最优选择(因为轮到对方)
            dp[i][j] = max(piles[i] - dp[i + 1][j],
                           piles[j] - dp[i][j - 1]);
        }
    }

    // 如果最终净胜分 > 0,则先手必胜
    return dp[0][n - 1] > 0;
}

石子游戏(区间DP):

说明:给你一个石子堆数组 stones,每次可以选择两个相邻的石子堆合并成一个新堆,代价为这两堆石子的数量之和。合并后的新石子堆仍可以与相邻的堆继续合并。最终只剩一堆石子,求最小总合并代价。

// 初始化
vector> dp(n, vector(n, 0));
vector prefix(n + 1, 0); // 前缀和,方便计算区间总和
for (int i = 0; i < n; ++i) {
    prefix[i + 1] = prefix[i] + stones[i];
}

// 递推公式
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + prefix[j + 1] - prefix[i]);


// 返回值
return dp[0][n - 1];

一个完整的示例代码:

#include 
#include 
using namespace std;

int stoneGame(vector& stones) {
    int n = stones.size();
    // 前缀和数组
    vector prefix(n + 1, 0);
    for (int i = 0; i < n; ++i)
        prefix[i + 1] = prefix[i] + stones[i];

    // 区间 DP 表
    vector> dp(n, vector(n, 0));

    // 区间长度从2开始枚举
    for (int len = 2; len <= n; ++len) {
        for (int i = 0; i + len - 1 < n; ++i) {
            int j = i + len - 1;
            dp[i][j] = INT_MAX;
            for (int k = i; k < j; ++k) {   
               dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + prefix[j + 1] - prefix[i]);
            }
        }
    }

    return dp[0][n - 1];
}

你可能感兴趣的:(动态规划,算法,c++,矩阵,数据结构,leetcode)