问题是找到求和数n所需的最小平方数。
一些例子:
min[ 1] = 1 (1²)
min[ 2] = 2 (1² + 1²)
min[ 4] = 1 (2²)
min[13] = 2 (3² + 2²)
我知道Lagrange's four-square theorem表示任何自然数都可以表示为四个方格的总和。
我正在尝试使用DP来解决这个问题。
这就是我提出的(不正确)
min[i] = 1 where i is a square number
min[i] = min(min[i - 1] + 1, 1 + min[i - prev]) where prev is a square number < i
解决此问题的DP方法是什么?
答案 0 :(得分:14)
我不确定DP是否是解决此问题的最有效方法,但您要求使用DP。
min [i] = min(min [i-1] + 1,1 + min [i-prev])其中prev是平方数&lt;我
这很接近,我会写条件为
min[i] = min(1 + min[i - prev]) for each square number 'prev <= i'
注意,对于每个i
,您需要检查prev
的不同可能值。
这是Java中的简单实现。
Arrays.fill(min, Integer.MAX_VALUE);
min[0] = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j*j <= i; ++j) {
min[i] = Math.min(min[i], min[i - j*j] + 1);
}
}
答案 1 :(得分:5)
我觉得你很亲密......
你正在接受两个术语的min(),每个术语都是min[i - p] + 1
,其中p是1或其他一些正方形&lt;岛
要解决此问题,只需将min[i - p] + 1
的min()超过所有 p(其中p是平方&lt; i)。
那将是一个正确的方式。可能有更快的方式。
此外,如果您提供min[]
和min()
个不同的名称,它可能有助于提高可读性。 : - )
P.S。上述方法要求您明确地或作为DP框架的一部分记住min[]
。否则,由于递归,算法的复杂性将类似于O(sqrt(n)!): - p尽管平均情况可能要好得多。
P.P.S。请参阅@ Nikita的答案以获得良好的实施方案。我将添加以下优化...(我不是在挑剔他的实现 - 他把它作为一个简单的实现。)
j*j*2 <= i
甚至是j*j*4 <= i
。我是这么认为的,但我还没有完全了解它。对于大i,在内循环之前计算j的限制会更快,并且在循环终止条件下直接比较j,而不是在每个内循环迭代中对j进行平方。 E.g。
float sqrti = Math.sqrt(i);
for (int j = 1; j <= sqrti; ++j) {
另一方面,无论如何你需要j ^ 2进行递归步骤,所以只要你存储它,你也可以使用它。
答案 2 :(得分:0)
对于多样性,这是另一个答案:
将minsq [i,j]定义为总和为i的{1 ^ 2,2 ^ 2,...,j ^ 2}的最小平方数。然后递归是:
minsq[i, j] = min(minsq[i - j*j, j] + 1, minsq[i, j - 1])
即,要计算minsq [i,j],我们要么使用j ^ 2,要么我们不使用。我们对n的回答是:
minsq[n, floor(sqrt(n))]
这个答案可能在概念上比前面提到的更简单,但在代码方面它更加困难,因为需要小心基本情况。两个答案的时间复杂度渐近相同。
答案 3 :(得分:0)
我提出了一种通用的非常有效的动态编程算法,用于找到给定功率的最小正整数,以便在JavaScript中达到给定目标。
例如,要获得具有4次幂的整数的50000,结果将为[10,10,10,10,10]
或达到18571,并且将产生具有7次幂的整数[3,4]
。该算法甚至可以使用合理的幂,例如用 3 / 5 的整数达到222 幂[ 32, 32, 243, 243, 243, 3125 ]
< / p>
function getMinimumCubes(tgt,p){
var maxi = Math.floor(Math.fround(Math.pow(tgt,1/p))),
hash = {0:[]},
pow = 0,
t = 0;
for (var i = 1; i <= maxi; i++){
pow = Math.fround(Math.pow(i,p));
for (var j = 0; j <= tgt - pow; j++){
t = j + pow;
hash[t] = hash[t] ? hash[t].length <= hash[j].length ? hash[t]
: hash[j].concat(i)
: hash[j].concat(i);
}
}
return hash[tgt];
}
var target = 729,
result = [];
console.time("Done in");
result = getMinimumCubes(target,2);
console.timeEnd("Done in");
console.log("Minimum number of integers to square and add to reach", target, "is", result.length, "as", JSON.stringify(result));
console.time("Done in");
result = getMinimumCubes(target,6);
console.timeEnd("Done in");
console.log("Minimum number of integers to take 6th power and add to reach", target, "is", result.length, "as", JSON.stringify(result));
target = 500;
console.time("Done in");
result = getMinimumCubes(target,3);
console.timeEnd("Done in");
console.log("Minimum number of integers to cube and add to reach", target, "is", result.length, "as", JSON.stringify(result));
target = 2017;
console.time("Done in");
result = getMinimumCubes(target,4);
console.timeEnd("Done in");
console.log("Minimum number of integers to take 4th power and add to reach", target, "is", result.length, "as", JSON.stringify(result));
target = 99;
console.time("Done in");
result = getMinimumCubes(target,2/3);
console.timeEnd("Done in");
console.log("Minimum number of integers to take 2/3th power and add to reach", target, "are", result);
&#13;