力扣每日一题---1547. 切棍子的最小成本

发布时间:2024年01月20日

?

? ? ? ? //当我们将棍子分段之后,我们是不是想到了怎么组合这些棍子

? ? ? ? //并且这些棍子有一个性质就是只能与相邻的进行组合

? ? ? ? //暴力搜索的话复杂度很高

? ? ? ? //在思考暴力搜索的时候,我们发现一个规律

? ? ? ? //比如棍子长度1 2 1 1 2

? ? ? ? //那么与最后一个2组合的棍子有,1 2,1 1 2,2 1 1 2,1 2 1 1 2

? ? ? ? //与最后一个1组合的棍子有,1 1,2 1 1,1 2 1 1

? ? ? ? //发现一个很显然的规律,能与前面组合的只有前面已经组合过的才能组合在一起

? ? ? ? //这是左边,那么当然还有右边

? ? ? ? //同理也是

? ? ? ? //然后根据规律总结一下公式

? ? ? ? //假设1 2 1 1 2,下标对应0 1 2 3 4

? ? ? ? //设f[i][j],表示组成这个区间的棍子的成本

? ? ? ? //那么想组成f[0][4] = f[0][3] + a[4];

? ? ? ? //f[1][4] = f[1][3] + a[4];

? ? ? ? //f[2][4] = f[2][3] + a[4];

? ? ? ? //f[3][4] = f[3][3] + a[4];

? ? ? ? //从这里又能看出我们组合肯定是根据范围从小到大进行组合的

? ? ? ? //比如f[1][3] = f[1][2] + f[2][3];那么在统计范围大的区间时

? ? ? ? //是由前面一个小范围推过来的,所以故此在计算大范围之前先统计小范围

? ? ? ? //故这就是动态规划的阶段

? ? ? ? //本题中我们求的是最小成本,那么需要把所有能组成f[0][4]的最小成本在推导时取个min就可以了

class Solution {
public:
    int minCost(int n, vector<int>& cuts) 
    {
        sort(cuts.begin(),cuts.end());
        vector<int> a;
        int prev = 0;
        for(int i = 0;i < cuts.size();i++)
        {
            a.push_back(cuts[i] - prev);
            prev = cuts[i];
        }
        a.push_back(n - prev);
        
        //当我们将棍子分段之后,我们是不是想到了怎么组合这些棍子
        //并且这些棍子有一个性质就是只能与相邻的进行组合
        //暴力搜索的话复杂度很高
        //在思考暴力搜索的时候,我们发现一个规律
        //比如棍子长度1 2 1 1 2
        //那么与最后一个2组合的棍子有,1 2,1 1 2,2 1 1 2,1 2 1 1 2
        //与最后一个1组合的棍子有,1 1,2 1 1,1 2 1 1
        //发现一个很显然的规律,能与前面组合的只有前面已经组合过的才能组合在一起
        //这是左边,那么当然还有右边
        //同理也是
        //然后根据规律总结一下公式
        //假设1 2 1 1 2,下标对应0 1 2 3 4
        //设f[i][j],表示组成这个区间的棍子的成本
        //那么想组成f[0][4] = f[0][3] + a[4];
        //f[1][4] = f[1][3] + a[4];
        //f[2][4] = f[2][3] + a[4];
        //f[3][4] = f[3][3] + a[4];
        //从这里又能看出我们组合肯定是根据范围从小到大进行组合的
        //比如f[1][3] = f[1][2] + f[2][3];那么在统计范围大的区间时
        //是由前面一个小范围推过来的,所以故此在计算大范围之前先统计小范围
        //故这就是动态规划的阶段
        //本题中我们求的是最小成本,那么需要把所有能组成f[0][4]的最小成本在推导时取个min就可以了
        

        //1 2 1 1 2
        int f[110][110];
        memset(f,0x3f3f3f3f,sizeof(f));
        vector<int> b(a.size() + 1);
        for(int i = 0;i < a.size();i++) b[i + 1] = a[i];
        for(int i = 1;i <= a.size();i++) f[i][i] = 0;

        int s[110];
        memset(s,0,sizeof(s));
        for(int i = 1;i <= a.size();i++) s[i] = s[i - 1] + b[i]; 

        for(int len = 2;len <= a.size();len++)//枚举的范围和阶段
        {
           for(int l = 1;l + len - 1<= a.size();l++)//确定范围,把当前阶段的状态都枚举出来
           {
                int r = l + len - 1;
                for(int k = l;k < r;k++)//确定好范围之后,我们就可以更新当前范围的状态了
                //怎么样保证不漏掉呢,只要枚举l <= k < r之间的k就行,可以保证所有状态都有
                { 
                  f[l][r] = min(f[l][r],f[l][k] + f[k + 1][r] + s[r] - s[l - 1]);
                }
           }
        }
        return f[1][a.size()];
    }
};

文章来源:https://blog.csdn.net/txh1873749380/article/details/135719471
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。