题目
最少立方数之和
链接:https://www.nowcoder.com/questionTerminal/4bc284dc9d0144628a722eb5d1191ef3?toCommentId=3672120
时间限制:C/C++ 1秒,其他语言2秒空间限制:C/C++ 64M,其他语言128M
算法知识视频讲解
给出一个数字N(0<N<1000000),将N写成立方数和的形式,求出需要的最少立方数个数。
例如N=17,1+8+8 = 17,最少需要3个立方数,则输出3。
N= 28,1+1+1+1+8+8+8=28, 需要7个立方数,1+27=28,需要2个立方数,所以最少立方数为2,则输出2。
输入描述:
一个数字N(0<N<1000000)
输出描述:
最少立方数个数
示例1
输入
28
输出
2
思路与代码
1.动态规划
借鉴至评论区
设dp[n]为组成 n需要的最少立方数个数
精髓所在:找的是所有差一步可以组成n的方案,求最小值加一;
dp[n] = 1 + min(dp[n-1],dp[n-8],dp[n-27],…) 要求n-iii>=0
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner input = new Scanner(System.in);
int n = input.nextInt();
int[] dp = new int[n+1];
dp[0] = 0;dp[1] = 1;
for(int i = 2;i<=n;i++){
int min = Integer.MAX_VALUE;//用于保存最小的个数
for(int j = 1;j*j*j<=i;j++){//找到最小的
min = Math.min(min,dp[i-j*j*j]);
}
dp[i] = min + 1;
}
//
System.out.println(dp[n]);
}
}
2.dfs
首先生成小于N的立方数,存入集合中,接下来用N对集合中一个个立方数从大到小进行相减,最后如果刚好等于0,即成功,若不等于0则退出递归进行下一次循环。在递归中再加上判定统计立方数的数量是否大于目前最小立方数之和的剪枝操作。时间复杂度稍高,但是容易理解,也能通过所有测试用例
public class Main {
static int min = Integer.MAX_VALUE;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
//把小于n的立方数装进集合
List<Integer> al = new ArrayList<>();
for (int i = 1; i < 100; i++) {
if(Math.pow(i, 3)>n) {
break;
}else if (Math.pow(i, 3)==n) {
System.out.println(1);
return;
}else {
al.add((int)Math.pow(i, 3));
}
}
int sum = 0;
dfs(n,sum,al,al.size()-1);
System.out.println(min);
}
private static void dfs(int n, int sum, ArrayList<Integer> al,int begin) {
if(n==0) {//刚好够装,判定目前的总个数(sum)是否小于最小的,是的话min等于目前的sum
if(sum<min) {
min = sum;
}
}
if(n<0||sum>min) {//n小于0,不够装 return || 使用次方数个数已经超过了目前最小的次方数 return
return;
}
for (int i = begin; i >=0; i--) {
dfs(n-al.get(i), sum+1, al, i);
}
}
}