无法设计有限结果的递归

时间:2012-05-25 19:09:11

标签: java algorithm recursion

我无法解决这个问题;从昨天开始一直困扰着我(抱歉,我之前发布了这个,然后将其删除,因为我以为我解决了它,但结果却是我修复的另一个错误)。我正在尝试简单地获取一个项目列表和一个范围,并找到允许所有项目使用的组合。

这是一个例子:想象你有4个项目(苹果,梨,桃和橙),并希望至少20%的篮子包含每个项目,最大值为60%。例如,你可以有25%,25%,25%,25%的每个项目或30%,30%,20%,20%等,但0%,0%,50%,50%不因为指定的最小%是20%而工作。

该程序运行正常,但它使用的项目少于整个列表(而不是每个解决方案中的4个项目,一些解决方案包含2或3个项目,这不是我想要的)。如果我发送一个包含4个项目的列表,我想要使用所有4个项目的组合,而不是更少。我不希望这样,因为我打算使用大型列表,我希望大小只是所有项目,而不是小于%。以下是使用上述信息的示例(4项,20-60%范围):

good:
 apples = 22
 pears  = 24
 peach  = 25
 orange = 29
 total: 100%

bad:
 apples = 0
 pears  = 0
 peach  = 40
 orange = 60
 total: 100%
 // Although total is correct, the example fails because
 // the minimum of 20% per item was not obeyed.

我真的很困惑为什么会发生这种情况,但如果我不得不打赌,我认为这是我的递归采取列表中的项目数量并在发回之前减去一个项目的方式。它在方法recursion_part

private static void recursion_part(int k, int sum, int[] coeff) {
    //k is number of items in the list(in this example its 4(0-3), sum is the remaining total percent to break down, coeff is the template to store values
    //this recursively takes the sum and tries to find lower values of it until it equals zero using the bounds given
    for (int c = low_bound[k]; c <= high_bound[k]; c++) {  
        coeff[k] = c;
        int[] newcoeff = Arrays.copyOf(coeff, coeff.length);
        if (c - sum == 0) {
        results.add(newcoeff);
        printresults(newcoeff);
        break;
    } else if (k > 0) {
        recursion_part(k - 1, sum - c, newcoeff);
    }
}
}

我想在更大的列表上工作,我认为如果它计算了很多我不关心的结果,那将是一个问题。如何重新设计此选项以仅处理列表中的所有项目并保持在范围限制内?

我想过一个方法来检查列表中有多少个零,然后如果它低于列表的大小则会中断,但是我得到空白结果的事实意味着它的处理项少于我的列表我认为设计这个程序更好,所以它不会浪费资源。

这是整个代码(它按照描述的方式工作,但如上所述给出零结果):

import java.util.ArrayList;
import java.util.Arrays;


public class recursion_percent_returner {
    static final int target_percent = 100;
    static final String[] names = new String[] {"apples", "pears", "peach", "orange" };
    static int[] low_bound = new int[names.length];
    static int[] high_bound = new int[names.length];
    static ArrayList results =  new ArrayList(); //queue to store results
    static int[] default_coeff = new int[names.length];

    public static void main(String[] args) {
        System.out.println("starting..");
        System.out.println("list size " + names.length);
        Arrays.fill(low_bound, 20); //fills the min list with default value
        Arrays.fill(high_bound, 60); //fills the max list with default value
        recursion_part(names.length-1,target_percent,default_coeff);
        System.out.println("total size of results are " + results.size());
    }

    private static void recursion_part(int k, int sum, int[] coeff) {
        //k is number of items in the list(in this example its 4(0-3), sum is the remaining total percent to break down, coeff is the template to store values
        //this recursively takes the sum and tries to find lower values of it until it equals zero using the bounds given
        for (int c = low_bound[k]; c <= high_bound[k]; c++) {  
            coeff[k] = c;
            int[] newcoeff = Arrays.copyOf(coeff, coeff.length);
            if (c - sum == 0) {
                results.add(newcoeff);
                printresults(newcoeff);
                break;
            } else if (k > 0) {
                recursion_part(k - 1, sum - c, newcoeff);
            }
        }
    }

    private static void printresults(int[] newcoeff) {      
        for (int x = 0; x<newcoeff.length; x++) {
            System.out.println(names[x] + " = " + newcoeff[x]);
        }
        System.out.println("*********");

    }
}

谢谢,如果有更好的方法来实现我正在寻找的结果,请告诉我。

P.S。这不是家庭作业,我不是学生;我只是倾向于发现奇怪的声音代理问题。

修改:我包含了整个代码,但here's the output as well。这是2653解决方案的一小部分,它产生的不仅仅是我需要的。如果你简单地看一下,你会发现大多数都是正确的,但随着你的降低,你会看到并非所有的值都被使用;我只想要使用所有值的解决方案;应该没有0个值条目。

1 个答案:

答案 0 :(得分:7)

import java.util.*;

public class Distributor {

    private ArrayList<int[]> result =  new ArrayList <int[]> ();

    public Distributor (final String [] names, int [] low, int [] high) 
    {
        final int rest = 10;
        int minimum = 0;
        for (int l : low)
            minimum += l; 
        int [] sizes = new int [names.length];
        distribute (0, low, high, rest - minimum, sizes);
        System.out.println ("total size of results are " + result.size ());
        for (int [] ia : result)
            show (ia, low); 
    }

    public static void main (String [] args) {
        final String [] names = new String [] {"a", "b", "c"};
        int [] low = new int [] {2, 2, 1};
        int [] high = new int [] {3, 4, 6};
        new Distributor (names, low, high);
    }

    /*
        distribute the rest of values over the elements in sizes, beginning with index i.           
    */
    void distribute (int i, int [] low, int [] high, final int rest, int [] sizes) {
        // System.out.println (i + " " + rest + " " + sizes);
        if (i == sizes.length - 1) {
            if (rest < high [i]) {
                sizes[i] = rest; 
                result.add (Arrays.copyOf (sizes, sizes.length));
            }
        }
        else 
            for (int c = 0; 
                c <= java.lang.Math.min (high [i] - low [i], rest); 
                ++c) {  
                sizes [i] = c;
                    distribute (i + 1, low, high, rest - c, sizes);                 
            }
    }

    private static void show (int [] arr, int [] low) {      
        for (int x = 0; x < arr.length; x++) {
            System.out.print (" " + (arr [x] + low[x]));
        }
        System.out.println ();
    }
}

长变量名称更好,如果它们比短变量更清晰。但它们本身并没有更多的价值。

更多:坚持命名注释,它是Java中的CamelCase,not_funky_underlines。

好的 - 为什么低和高应该是静态的?我没有为'名字'和'结果'向这个方向努力。仍然是一个删除静态修改器的练习。

好的 - 我的印象是,总和需要总是100,而不是更少,也不要超过100.因此,如果4x20%是最小值,则最多不能达到60%。但是我知道这些值是可变的,而在另一个设置中,你可能最小值为4x10%,然后,最多60%是有意义的。我没有为此目的测试代码。

但我将其余的最小值(4 * 20%)减去分布,所以你必须为最终结果添加这些值。

递归分配函数以终止条件开始:到达最后一个元素。现在剩下的 - 可能是多少 - 必须放在最后一个元素上。

否则,您将获取此元素的所有可能值,并分配其余元素。

更新

我更改了代码以处理上限,并简化了一方面的示例,因为它现在只使用3个元素,最多10个而不是100.输出显示实际值(min + variable)部分)并且算法仅添加不违反上限约束的解。

示例输出:

 2 2 6
 2 3 5
 2 4 4
 3 2 5
 3 3 4
 3 4 3
total size of results are 6