#include <vector>
class Solution {
  public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param monsterLength int整型 线段长度
     * @param monsterPoint int整型vector 切割点位置
     * @return int整型
     */
    int attackMonster(int monsterLength, vector<int>& monsterPoint) {
        int numOfPoints = monsterPoint.size() + 2;
        vector<int> points(numOfPoints);
        points[0]=0;
        points[numOfPoints-1]=monsterLength;
        for (int i=1; i<numOfPoints-1; i++) {
            points[i]=monsterPoint[i-1];
        }
        sort(points.begin(),points.end());
        for (int i:points) {
            cout<<i<<"|";
        }
        // monsterPoint加上头尾两个点
        // dp[i][j]表示从第i个点到第j个点,这中间的最小切割成本
        // 相邻点之间切割成本为0,所以dp[i][i+1]=0
        // -1表示该值尚未被初始化
        vector<vector<int>> dp(numOfPoints, vector<int>(numOfPoints, -1));
        for (int i = 0; i < numOfPoints-1; i++) {
            // 一跳邻居的间距为0
            dp[i][i + 1] = 0;
        }
        for (int j = 2; j < numOfPoints; j++) {// 从2跳邻居开始一直到numOfPoints跳邻居
            for (int i = 0; i+j < numOfPoints; i++) {
                // 计算j跳邻居间距dp[i][i+j]
                int minPart=dp[i][i+1]+dp[i+1][i+j];
                for (int k=2; k<j; k++) {
                    int tempPart=dp[i][i+k]+dp[i+k][i+j];
                    if (tempPart<minPart) {
                        minPart=tempPart;
                    }
                }
                dp[i][i+j]=minPart+points[i+j]-points[i];
            }
        }
        for (int i=0; i<numOfPoints; i++) {
            for (int j=0; j<numOfPoints; j++) {
                cout<<dp[i][j]<<",";
            }
            cout<<"|";
        }
        return dp[0][numOfPoints-1];
    }
};

动态规划,monsterPoint加上头尾两个点,对于这N+2个点,开始搜索

dp[i][i+j]表示从第i个点到第i+j个点,这中间的最小切割成本(开区间)

初始化:相邻点之间切割成本为0,所以dp[i][i+1]=0

对j从2开始遍历,j表示“邻居跳数”,从2跳邻居开始算总成本

保证计算 j 跳邻居时,跳数比j小的成本已经全部计算过了

然后对位置i进行遍历

从 i 跳到 i+j 要跳两次,第一次跳到切割点,因此 k 对切割点进行遍历

三次遍历实现最后的算法,复杂度n^3