蛮力算法可以扩展吗?

时间:2011-09-01 02:32:09

标签: algorithm hadoop scalability

我有一个数学问题,我通过反复试验解决(我认为这被称为暴力),当有一些选项时程序工作正常,但随着我添加更多变量/数据需要更长更长时间跑。

我的问题是,虽然原型有效,但它对数以千计的变量和大数据集很有用;所以,我想知道是否有可能扩展蛮力算法。我该如何进行缩放呢?

我开始学习并玩Hadoop(和HBase);虽然它看起来很有希望,但我想验证我正在尝试做的事情并非不可能。

如果它有帮助,我用Java编写程序(如果可能的话可以使用它),但最终将它移植到Python,因为我觉得它更舒服。

更新为了提供更多洞察力,我想我会添加一个简化版本的代码来获取想法。基本上如果我知道总和是100,我试图找到可以等于它的所有变量组合。这很简单,在我的版本中我可能会使用更大的数字和更多的变量。它是Diophantine,我相信没有算法可以在没有暴力的情况下解决它。

int sum = 100;
int a1 = 20;
int a2 = 5;
int a3 = 10;
for (int i = 0; i * a1 <= sum; i++) {
    for (int j = 0; i * a1 + j * a2 <= sum; j++) {
        for (int k = 0; i * a1 + j * a2 + k * a3 <= sum; k++) {
            if (i * a1 + j * a2 + k * a3 == sum) {
              System.out.println(i + "," + j + "," + k);
            }
        }
    }   
}

我是编程的新手,如果我没有正确地构思这个问题,我很抱歉。这是一个普遍的问题。

3 个答案:

答案 0 :(得分:29)

答案 1 :(得分:2)

根据定义,暴力算法是愚蠢的。使用更聪明的算法(如果有的话)你会好得多。一个更好的算法将减少已完成的工作,希望在某种程度上你可以做到这一点,而无需“扩展”到多台机器。

无论算法如何,当所需的数据量或计算能力如此之大以至于您需要使用类似Hadoop之类的东西时,就会出现这种情况。但通常,我们真的在这里谈论大数据。这些天你已经可以用一台PC做很多事了。

答案 2 :(得分:1)

解决此问题的算法对于我们学习手动数学除法的过程是关闭的,或者也是从十进制转换为另一个基数,如八进制或十六进制 - 除了两个示例只查找单个规范解决方案。

为确保递归结束,对数据数组进行排序非常重要。为了提高效率并限制递归次数,从较高的数据值开始也很重要。

具体来说,这是针对此问题的Java递归实现 - 在理论上为每个递归提供了结果向量coeff的副本。

import java.util.Arrays;

public class Solver
{
    public static void main(String[] args)
    {
        int target_sum = 100;
        // pre-requisite: sorted values !!
        int[] data = new int[] { 5, 10, 20, 25, 40, 50 };
        // result vector, init to 0
        int[] coeff = new int[data.length];
        Arrays.fill(coeff, 0);
        partialSum(data.length - 1, target_sum, coeff, data);
    }

    private static void printResult(int[] coeff, int[] data) {
        for (int i = coeff.length - 1; i >= 0; i--) {
            if (coeff[i] > 0) {
                System.out.print(data[i] + " * " + coeff[i] + "   ");
            }
        }
        System.out.println();
    }

    private static void partialSum(int k, int sum, int[] coeff, int[] data) {
        int x_k = data[k];
        for (int c = sum / x_k; c >= 0; c--) {
            coeff[k] = c;
            if (c * x_k == sum) {
                printResult(coeff, data);
                continue;
            } else if (k > 0) {
                // contextual result in parameters, local to method scope
                int[] newcoeff = Arrays.copyOf(coeff, coeff.length);
                partialSum(k - 1, sum - c * x_k, newcoeff, data);
                // for loop on "c" goes on with previous coeff content
            }
        }
    }
}

但现在代码处于特殊情况:每个coeff的最后一次值测试为0,因此不需要复制。

作为复杂性估计,我们可以将递归调用的最大深度用作data.length * min({ data })。当然,它不能很好地扩展,限制因素是堆栈跟踪内存(-Xss JVM选项)。对于较大的data集,代码可能会因堆栈溢出错误而失败。

为了避免这个缺点,&#34; derecursion&#34;过程很有用。它包括用编程堆栈替换方法调用堆栈以存储执行上下文以便稍后处理。这是代码:

import java.util.Arrays;
import java.util.ArrayDeque;
import java.util.Queue;

public class NonRecursive
{
    // pre-requisite: sorted values !!
    private static final int[] data = new int[] { 5, 10, 20, 25, 40, 50 };

    // Context to store intermediate computation or a solution
    static class Context {
        int k;
        int sum;
        int[] coeff;
        Context(int k, int sum, int[] coeff) {
            this.k = k;
            this.sum = sum;
            this.coeff = coeff;
        }
    }

    private static void printResult(int[] coeff) {
        for (int i = coeff.length - 1; i >= 0; i--) {
            if (coeff[i] > 0) {
                System.out.print(data[i] + " * " + coeff[i] + "   ");
            }
        }
        System.out.println();
    }

    public static void main(String[] args)
    {
        int target_sum = 100;
        // result vector, init to 0
        int[] coeff = new int[data.length];
        Arrays.fill(coeff, 0);

        // queue with contexts to process
        Queue<Context> contexts = new ArrayDeque<Context>();
        // initial context
        contexts.add(new Context(data.length - 1, target_sum, coeff));

        while(!contexts.isEmpty()) {
            Context current = contexts.poll();
            int x_k = data[current.k];
            for (int c = current.sum / x_k; c >= 0; c--) {
                current.coeff[current.k] = c;
                int[] newcoeff = Arrays.copyOf(current.coeff, current.coeff.length);
                if (c * x_k == current.sum) {
                    printResult(newcoeff);
                    continue;
                } else if (current.k > 0) {
                    contexts.add(new Context(current.k - 1, current.sum - c * x_k, newcoeff));
                }
            }
        }
    }
}

从我的观点来看,在单个线程执行中很难提高效率 - 堆栈机制现在需要使用coeff数组副本。

相关问题