2

这是我的问题的一些背景(不是家庭作业)。我在杂货店有 4 种物品可供选择,我想弄清楚我的购物篮中每种物品的百分比,但我设置了一个范围,即任何物品都不能低于 20% 且不超过 60%。该程序当前从 0 开始并向上运行(在这种情况下,0 是最小值 20,高于它的任何值都等于它是最小值的百分比)。使用上面最小值为 20 的示例,那么 [20,0,0,0]将等于 40 + 20 + 20 + 20 = 100 并为所有项目生成排列。

运行后,我意识到(使用上面的例子)第一项是[20,0,0,0],最后一项是[0,0,0,20]。我通过将所有结果与自身的反向版本进行比较来测试它,它们都存在,所以我想我可以找到一种方法,通过只处理一半列表然后获取结果并将它们翻转过来,将我的处理时间缩短一半。当我开始检查反向匹配时,我遇到了一个问题,而程序仍在生成结果,似乎没有一个点可以翻转并开始复制(我希望它正好在一半时会这样做)。这是结果的输出,第一列是结果本身,第二列是它的反转版本的索引(-1 表示未找到)。它从全 -1 开始,然后开始找到一些反向匹配,但仍然有许多 -1,然后它最终过渡到所有重复的结果,但它似乎以可预测的清晰方式进行。

我的最终目标是使用更大的列表,并且我试图找到一种方法来生成尽可能多的数据,因此任何关于如何识别模式或其他速度改进的建议都会很棒。我在想,在这种情况下,我要么需要一种方法来识别模式一旦完全开发(即不再有机会-1),要么调整算法以便它以完全切换而不是缓慢的部分变化的顺序生成。

如果有帮助,这是我正在使用的代码(注意:项目和范围的数量是变量,所以我试图找到一个通用模式,而不是特定于任何硬数字):

import java.util.*;

public class Distributor {
    //correct output is 1771
    private ArrayList<int[]> result =  new ArrayList <int[]> ();
    /*

    */
    public Distributor (final String [] names, int [] low, int [] high) 
    {
        final int rest = 100;
        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 ());
    }

    public static void main (String [] args) {
        System.out.println("starting..Hold on!!");
        final String [] names = new String [] {"a", "b", "c", "d"}; //name of items
        int [] low = new int [names.length];
        int [] high = new int [names.length];
        Arrays.fill(low, 20); //auto fill the range of items with a min/max range
        Arrays.fill(high, 60);
        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) {  
        if (i == sizes.length - 1) { //this area procesess the final item and adds it to the solution queue
            if (rest < high [i]) {
                sizes[i] = rest; 
                checkResultsDuringRuntime(Arrays.copyOf (sizes, sizes.length),result);
                result.add (Arrays.copyOf (sizes, sizes.length));
            }
        }
        else {
            int StartLoop = 0;
            //this area checks if the remaining value can be reached used the max values of remaining items
            //if its not possible then the current min range of the loop must be increased
            if ( rest > (low.length-(i + 1))*high[i]) {
                System.out.println("rest is higher than high");
                StartLoop = (rest - (low.length-(i + 1))*high[i]);
            }
            //this area runs a loop for each coeffient and then sends it back to this function to further processing
            for (int c = StartLoop; 
                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 checkResultsDuringRuntime(int[] defaultlist, ArrayList<int[]> result2) {
        //check results list for list
        //first lets flip the list around
        int[] ReversedList = new int[defaultlist.length];
        for (int x = defaultlist.length-1, y=0; x>=0;x--, y++) {
            ReversedList[y] = defaultlist[x];
        }       
        int MatchLocation = -1;
        for (int[] item : result2) {
            if ( Arrays.toString(item).equals(Arrays.toString(ReversedList)))
            {   
                //System.out.println("theres a match");
                MatchLocation = result2.indexOf(item);
            }
        }
        System.out.println(Arrays.toString(defaultlist) + " = " + MatchLocation);
    }
}

输出: http: //pastebin.com/6vXRvVit

编辑:该程序不会生成重复项。它的产生似乎最终会逆转。我想尝试捕获反向排列将全部匹配现有结果的点,因此我无需进一步处理数据,而是可以反转现有结果。查看上面的输出以了解我所描述的内容。

4

2 回答 2

1

我不完全理解这个问题,但有一个解决类似问题的技巧。假设你想生成 3 个从 1 到 6 的数字,例如 [1, 4, 2],但你想忽略 dups;即 [1,2,3] = [3,2,1]

就是这样:

for(int i=1; i <= 6; i++) {
    for(int j=i+1; j <= 6; j++) {
        for(int k=j+1; k <= 6; k++) {
            System.out.println(i+","+j+","+k);
            }
        }
    }

输出将包括所有可能性,但没有重复的排列。

编辑 - 这是输出......

1,2,3
1,2,4
1,2,5
1,2,6
1,3,4
1,3,5
1,3,6
1,4,5
1,4,6
1,5,6
2,3,4
2,3,5
2,3,6
2,4,5
2,4,6
2,5,6
3,4,5
3,4,6
3,5,6
4,5,6

编辑 2 - 对于 OP 的问题,其中有 4 个项目的限制为 20 和 60,有 101,270 个排列。假设整数百分比是可以接受的。也就是说,25%,而不是 25.1%

编辑 3 - 是的,这个很有趣。OP说百分比必须加起来为100。我错过了。有 108 种可能性。他们是:

1 : [20,20,20,40]
2 : [20,20,21,39]
3 : [20,20,22,38]
4 : [20,20,23,37]
5 : [20,20,24,36]
6 : [20,20,25,35]
7 : [20,20,26,34]
8 : [20,20,27,33]
9 : [20,20,28,32]
10 : [20,20,29,31]
11 : [20,20,30,30]
12 : [20,21,21,38]
13 : [20,21,22,37]
14 : [20,21,23,36]
15 : [20,21,24,35]
16 : [20,21,25,34]
17 : [20,21,26,33]
18 : [20,21,27,32]
19 : [20,21,28,31]
20 : [20,21,29,30]
21 : [20,22,22,36]
22 : [20,22,23,35]
23 : [20,22,24,34]
24 : [20,22,25,33]
25 : [20,22,26,32]
26 : [20,22,27,31]
27 : [20,22,28,30]
28 : [20,22,29,29]
29 : [20,23,23,34]
30 : [20,23,24,33]
31 : [20,23,25,32]
32 : [20,23,26,31]
33 : [20,23,27,30]
34 : [20,23,28,29]
35 : [20,24,24,32]
36 : [20,24,25,31]
37 : [20,24,26,30]
38 : [20,24,27,29]
39 : [20,24,28,28]
40 : [20,25,25,30]
41 : [20,25,26,29]
42 : [20,25,27,28]
43 : [20,26,26,28]
44 : [20,26,27,27]
45 : [21,21,21,37]
46 : [21,21,22,36]
47 : [21,21,23,35]
48 : [21,21,24,34]
49 : [21,21,25,33]
50 : [21,21,26,32]
51 : [21,21,27,31]
52 : [21,21,28,30]
53 : [21,21,29,29]
54 : [21,22,22,35]
55 : [21,22,23,34]
56 : [21,22,24,33]
57 : [21,22,25,32]
58 : [21,22,26,31]
59 : [21,22,27,30]
60 : [21,22,28,29]
61 : [21,23,23,33]
62 : [21,23,24,32]
63 : [21,23,25,31]
64 : [21,23,26,30]
65 : [21,23,27,29]
66 : [21,23,28,28]
67 : [21,24,24,31]
68 : [21,24,25,30]
69 : [21,24,26,29]
70 : [21,24,27,28]
71 : [21,25,25,29]
72 : [21,25,26,28]
73 : [21,25,27,27]
74 : [21,26,26,27]
75 : [22,22,22,34]
76 : [22,22,23,33]
77 : [22,22,24,32]
78 : [22,22,25,31]
79 : [22,22,26,30]
80 : [22,22,27,29]
81 : [22,22,28,28]
82 : [22,23,23,32]
83 : [22,23,24,31]
84 : [22,23,25,30]
85 : [22,23,26,29]
86 : [22,23,27,28]
87 : [22,24,24,30]
88 : [22,24,25,29]
89 : [22,24,26,28]
90 : [22,24,27,27]
91 : [22,25,25,28]
92 : [22,25,26,27]
93 : [22,26,26,26]
94 : [23,23,23,31]
95 : [23,23,24,30]
96 : [23,23,25,29]
97 : [23,23,26,28]
98 : [23,23,27,27]
99 : [23,24,24,29]
100 : [23,24,25,28]
101 : [23,24,26,27]
102 : [23,25,25,27]
103 : [23,25,26,26]
104 : [24,24,24,28]
105 : [24,24,25,27]
106 : [24,24,26,26]
107 : [24,25,25,26]
108 : [25,25,25,25]

我们注意到 60 的上限太大了——在最小值 20% 时无法添加其他三个项目。那将是 120%。

于 2012-05-26T23:35:34.213 回答
0

我建议使用布隆过滤器 ,它可以保证不会出现误报:

假阳性是可能的,但假阴性是不可能的;即查询返回“在集合内(可能是错误的)”或“绝对不在集合内”

Java实现

源代码

现在当然问题是比较数组是否相等,我建议您执行以下操作:

Arrays.sort(arrayToCompare);  
Arrays.equals(initialArray,arrayToCompare);

您承担了排序的开销,但它会告诉您两个数组是否相等,因此之前的布隆过滤器就足够了。

于 2012-05-26T23:31:28.357 回答