牛客题解 | 最少立方数之和

题目

题目链接

题解

题目难度:中等难度

知识点:动态规划、递归、动态数组

我们实现动态规划算法,常用的是2个实现套路,一个是自底向上,另外一个是自顶向下。无论是何种方式,我们都要明确动态规划的过程,把状态表示、状态转移、边界都考虑好。

方法(一):自底向上

简单来说就是根据初始状态,逐步推导到最终状态,而这个转移的过程,必定是一个拓扑序。如何理解这个拓扑序问题呢,甲总监下面有X,Y,Z三个小组,甲总监不会一拿到X组最优秀的三个人,就立马去跟A经理汇报,而是要等到Y,Z小组也选出来之后,也就是自己下面所有子问题都解决了,才会继续向汇报。

自底向上一般用来解决什么问题呢?

那就是可以轻松确定拓扑序的问题,例如线性模型,都是从左往右进行转移,区间模型,一般都是从小区间推导到大区间。自底向上的一个经典实现是斐波那楔数列的递推实现,即F[i] = F[i - 1] + F[i -2]。

#include<iostream>
#include<vector>
#define Maxn 1000010
using namespace std;
int main()
{            
    int n, t, i;
    cin &gt;&gt; n;
    vector<int> dp(n + 1,Maxn);
    dp[0]=0;
    for(t = 1; t &lt;= n; t++) {
        for(i = 1; i * i * i &lt;=t; i++) {
            dp[t]  = min(dp[t], dp[t - i * i * i]+1);
        }
    }
    cout &lt;&lt; dp[n] &lt;&lt; endl;
    return 0;
}

方法(二):自顶向下

从最终状态出发,如果遇到一个子问题还未求解,那么就先求解子问题。如果子问题已经求解,那么直接使用子问题的解,所以自顶向下动态规划又有一个形象生动的名字,叫做记忆化搜索,一般我们采用递归的方式进行求解。

自顶向下,我们一般用在树上面,因为我们根据父亲结点,很容易找到所有的子问题,也就是所有的子结点,而自底向上的话,我们要去统计这个结点的所有兄弟结点是否已经实现。会稍微复杂一点,而且比较难理解。

#include <iostream>
#include<vector>
#define Maxn 1000010
using namespace std;

int f( vector<int> &amp;dp,int n) {
    if(n==0) return 0;
    else if(dp[n]!=Maxn) return dp[n];
    else {
        int i = 1;
        while (i * i * i &lt;= n) {
            int r = n - (i * i * i);
            dp[n] = min(dp[n], 1 + f(dp,r));
            ++i;
        }
        return dp[n];
    }
}
   
int main() {
    int n;
    cin&gt;&gt;n;
    vector<int> dp(n + 1,Maxn);
    dp[0]=0;
    cout&lt;</int></int></vector></iostream></int></vector></iostream>
posted @ 2025-03-07 11:26  wangxiaoxiao  阅读(12)  评论(0)    收藏  举报