生成在Java中添加到100的12个数字的所有组合的有效方法

时间:2013-08-28 16:58:00

标签: java algorithm math permutation time-complexity

我在混合工厂生产了12种产品(称之为a-l),需要产生不同百分比的产品,总产量明显加起来为100%。

如下面的代码这样的简单方法可行,但效率非常低。有更高效的算法吗?

*编辑:如下所述,有效或无效计算可能性太多。我将此更改为仅混合中最多5个或12个产品,然后根据从12个产品中选择5个产品的方式运行它。

有些人指出的Python代码似乎可以解决组合中的可能性。但是我的Python很小(即0%),你们其中一个人能用Java来解释这个吗?我可以用Java(http://www.cs.colostate.edu/~cs161/Fall12/lecture-codes/Subsets.java

获得组合
public class Main {


public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {


   for(int a=0;a<=100;a++){
        for(int b=0;b<=100;b++){
             for(int c=0;c<=100;c++){
                 for(int d=0;d<=100;d++){
                     for(int e=0;e<=100;e++){
                          for(int f=0;f<=100;f++){
                                for(int g=0;g<=100;g++){
                                   for(int h=0;h<=100;h++){
                                       for(int i=0;i<=100;i++){
                                            for(int j=0;j<=100;j++){
                                               for(int k=0;k<=100;k++){
                                                      for(int l=0;l<=100;l++){

                                                    if(a+b+c+d+e+f+g+h+i+j+k+l==100)

                                                      {

                                            System.out.println(a+" "+b+" "+c+" "+d+" "+e+" "+f+" "+g+" "+h+" "+i+" "+j+" "+k+" "+l);



       }}}}}}}}}}}}}

}

}

4 个答案:

答案 0 :(得分:1)

为什么要这么难。想想简单的方法。

为了简化场景,请考虑随机生成5个数字。伪代码应该如下所示。

  1. 生成5个随机数,R1,R2 ... R5
  2. total =这5个随机数的总和。
  3. 用于生产的所有物品
    • 产品1 = R1 /总; //产生[i] = R [i] / total;

答案 1 :(得分:0)

请不要使用嵌套的for循环!改为使用递归:

public static void main(String[] args) {
    int N = 12;
    int goal = 100; 

    generate(N, 0, goal, new int[N]);
}

public static void generate(int i, int sum, int goal, int[] result) {
    if (i == 1) {
        // one number to go, so make it fit
        result[0] = goal - sum;
        System.out.println(Arrays.toString(result));
    } else {
        // try all possible values for this step
        for (int j = 0; j < goal - sum; j++) {
            // set next number of the result
            result[i-1] = j;
            // go to next step
            generate(i-1, sum + j , goal, result);
        }
    }
}

请注意,我仅针对N = 3goal = 5对此进行了测试。尝试生成所有这些可能性是绝对没有意义的(并且需要永远计算)。

答案 2 :(得分:0)

for(int a=0;a<=100;a++){
    for(int b=0;b<=50;b++){
         for(int c=0;c<=34;c++){
             for(int d=0;d<=25;d++){
                 for(int e=0;e<=20;e++){
                      for(int f=0;f<=17;f++){
                            for(int g=0;g<=15;g++){
                               for(int h=0;h<=13;h++){
                                   for(int i=0;i<=12;i++){
                                        for(int j=0;j<=10;j++){
                                           for(int k=0;k<=10;k++){
                                                  for(int l=0;l<=9;l++){

                                                if(a+b+c+d+e+f+g+h+i+j+k+l==100)

                                                  {

                                                // run 12 for loops for arranging the  
                                                // 12 obtained numbers at all 12 places      


   }}}}}}}}}}}}}

在原始方法(基于置换)中,迭代次数为102 ^ 12 = 1.268e24。即使第102次迭代是错误的,它也确实检查了第102次循环终止条件。 所以你在“for”循环中进行了102 ^ 12条件检查,除了“if”条件检查101 ^ 12次,总共2.4e24条件检查。

在我的解决方案(基于组合)中,对于外部12个循环,for循环检查的数量减少到6.243e15,&amp;
如果条件检查= 6.243e15。 现在,对于每个真正的“if”条件,for循环(即内部12循环)的no是12 ^ 12 = 8.9e12。 如果条件允许有x个真值。总状况检查

=没有内部for循环* x

= 8.9e12 * x + 6.243e15

我无法找到x的值。但是,我认为它不足以使总条件检查大于2.4e24

答案 3 :(得分:0)

让我们评论一下,你只能组合5个元素,其他7个是0%。试试这个:

for (i = 0; i < (1<<12); ++i) {
    if (count_number_of_1s(i) != 5) { continue; }
    for (j = 0; j < 100000000; ++j) {
       int [] perc = new int[12];
       int val = j;
       int sum = 0;
       int cnt = 0;
       for (k = 0; k < 12; ++k) {
         if (i & (1 << k)) {
            cnt++;
            if (cnt == 5) {
              perc[k] = 100 - sum;
            }
            else {
              perc[k] = val % 100;
              val /= 100;
            }
            sum += perc[k];
            if (sum > 100) { break; }
         }
         else { perc[k] = 0; }
       }
       if (sum == 100) {
         System.out.println(perc[0] + ...);
       }
    }
}

外部循环遍历使用12个项目的所有可能组合。您可以通过循环遍历1:2 ^ 12的所有数字来完成此操作,并且该数字的二进制表示中的1是您正在使用的元素。 count_number_of_1s是一个循环遍历参数中所有位并返回1个数的函数。如果这不是5,那么就跳过这个迭代,因为你说你最多只想要5个混合。 (有792个这样的案例)。

j循环遍历0:100中4个(非5个)项目的所有组合。有100 ^ 4个这样的案例。

内部循环遍历所有12个变量,对于i中位数为1的那些变量,则表示您正在使用该变量。您可以通过从j获取接下来的两位小数来计算百分比。对于第5项(cnt==5),您不需要数字,您可以通过从100减去来计算数字。

这将花费很长时间(分钟),但它不会像12个嵌套循环那样糟糕。