【发布时间】:2012-03-27 01:40:08
【问题描述】:
更新:为了帮助澄清我的要求,我发布了一些 Java 代码,可以理解这个想法。
不久前,我向question 询问了如何让算法分解一组数字,我的想法是给它一个数字列表(1,2,3,4,5) 和总数(10),它会找出每个数字的所有倍数,加起来就是总数('1*10' 或 '1*1,1*2,1*3,1*4' 或 '2*5' 等)。这是我做过的第一次编程练习,所以我花了一段时间才让它工作,但现在我想看看我是否可以扩展它。原始问题中的人说它是可扩展的,但我对如何做到这一点有点困惑。递归部分是我坚持缩放组合所有结果的部分的区域(它所指的表不可缩放,但应用缓存我能够使其快速)
我有以下算法(伪代码):
//generates table
for i = 1 to k
for z = 0 to sum:
for c = 1 to z / x_i:
if T[z - c * x_i][i - 1] is true:
set T[z][i] to true
//uses table to bring all the parts together
function RecursivelyListAllThatWork(k, sum) // Using last k variables, make sum
/* Base case: If we've assigned all the variables correctly, list this
* solution.
*/
if k == 0:
print what we have so far
return
/* Recursive step: Try all coefficients, but only if they work. */
for c = 0 to sum / x_k:
if T[sum - c * x_k][k - 1] is true:
mark the coefficient of x_k to be c
call RecursivelyListAllThatWork(k - 1, sum - c * x_k)
unmark the coefficient of x_k
我真的不知道如何线程/多处理 RecursivelyListAllThatWork 函数。我知道如果我向它发送一个较小的 K(它是列表中项目总数的整数),它将处理该子集,但我不知道如何将结果合并到子集中。例如,如果列表是[1,2,3,4,5,6,7,8,9,10],我发送它 K=3,那么只有 1,2,3 得到处理,这很好,但如果我需要包含 1 和 10 的结果呢?我试图修改表(变量 T),所以只有我想要的子集在那里,但仍然不起作用,因为就像上面的解决方案一样,它做了一个子集,但无法处理需要更广泛范围的答案。
我不需要任何代码,只要有人可以解释如何在概念上打破这个递归步骤,以便可以使用其他内核/机器。
更新:我似乎仍然无法弄清楚如何将 RecursivelyListAllThatWork 变成可运行的(我在技术上知道如何做到这一点,但我不明白如何更改 RecursivelyListAllThatWork 算法,以便它可以并行运行。其他部分只是为了让示例工作,我只需要在 RecursivelyListAllThatWork 方法上实现 runnable)。这是java代码:
import java.awt.Point;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class main
{
public static void main(String[] args)
{
System.out.println("starting..");
int target_sum = 100;
int[] data = new int[] { 10, 5, 50, 20, 25, 40 };
List T = tableGeneator(target_sum, data);
List<Integer> coeff = create_coeff(data.length);
RecursivelyListAllThatWork(data.length, target_sum, T, coeff, data);
}
private static List<Integer> create_coeff(int i) {
// TODO Auto-generated method stub
Integer[] integers = new Integer[i];
Arrays.fill(integers, 0);
List<Integer> integerList = Arrays.asList(integers);
return integerList;
}
private static void RecursivelyListAllThatWork(int k, int sum, List T, List<Integer> coeff, int[] data) {
// TODO Auto-generated method stub
if (k == 0) {
//# print what we have so far
for (int i = 0; i < coeff.size(); i++) {
System.out.println(data[i] + " = " + coeff.get(i));
}
System.out.println("*******************");
return;
}
Integer x_k = data[k-1];
// Recursive step: Try all coefficients, but only if they work.
for (int c = 0; c <= sum/x_k; c++) { //the c variable caps the percent
if (T.contains(new Point((sum - c * x_k), (k-1))))
{
// mark the coefficient of x_k to be c
coeff.set((k-1), c);
RecursivelyListAllThatWork((k - 1), (sum - c * x_k), T, coeff, data);
// unmark the coefficient of x_k
coeff.set((k-1), 0);
}
}
}
public static List tableGeneator(int target_sum, int[] data) {
List T = new ArrayList();
T.add(new Point(0, 0));
float max_percent = 1;
int R = (int) (target_sum * max_percent * data.length);
for (int i = 0; i < data.length; i++)
{
for (int s = -R; s < R + 1; s++)
{
int max_value = (int) Math.abs((target_sum * max_percent)
/ data[i]);
for (int c = 0; c < max_value + 1; c++)
{
if (T.contains(new Point(s - c * data[i], i)))
{
Point p = new Point(s, i + 1);
if (!T.contains(p))
{
T.add(p);
}
}
}
}
}
return T;
}
}
【问题讨论】:
-
tableGenerator 方法中“max_percent = 1”的原因是什么?
-
@YvesMartin 它用于限制结果,因此没有任何内容超过 100%,但忽略 tableGenerator 方法的细节,它只是提供一个表格来向您展示 RecursivelyListAllThatWork 的工作原理。所以鉴于该表格, RecursivelyListAllThatWork 可以线程化吗?
-
您是否知道表格生成器已经找到了问题的解决方案,而无需任何递归,而是通过尝试所有组合?这个工作真的很费钱,最后 RecursivelyListAllThatWork 也没用了。我已经发布了一个“真正的”递归实现作为原始问题的答案。您误解了伪代码中“T”的含义——如果答案是解决,它是一个谓词,它回答“真”。
-
@YvesMartin 我认为 T 表示该值是否可解......然后我需要 RecursivelyListAllThatWork 才能将所有结果汇总在一起?
-
好的,我现在明白会发生什么了。生成的表用于削减大量没有解决方案的递归调用。