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

 

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

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

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

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

        //比如棍子长度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()];
    }
};

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乖的小肥羊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值