7

この問題では、単純にアイテムのリストと範囲を取り、すべてのアイテムを使用できる組み合わせを見つけようとしています。

例を次に示します。4 つの商品 (リンゴ、ナシ、モモ、オレンジ) があり、バスケットの最小 20%、最大 60% にそれぞれを含めるとします。たとえば、各アイテムの 25%、25%、25%、25%、または 30%、30%、20%、20% などを指定できますが、0%、0%、50%、50% は指定できません。指定された min% が 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.

なぜこれが起こっているのか本当に混乱していますが、賭けなければならない場合、再帰がリスト内のアイテムの数を取り、それを送り返す前に1を引く方法だと思います. メソッド内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("*********");

    }
}

私は、自分が求めている結果を達成するためのより良い方法に対してオープンです。

ps これは宿題ではなく、私は学生ではありません。奇妙な響きのプロキシの問題を見つける傾向があります。

編集

コード全体を含めましたが、ここにも出力があります。これは 2653 ソリューションのスニペットで、必要以上に生成されています。簡単に見ると、ほとんどが正しいことがわかりますが、下に行くにつれて、すべての値が使用されているわけではないことがわかります。すべての値を使用しているソリューションのみが必要です。0 値エントリがあってはなりません。

4

1 に答える 1

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であるnamingConventionsに固執し、not_funky_underlines。

わかりました-なぜ低と高は静的でなければならないのですか?私は「名前」と「結果」についてこの方向で作業しませんでした。静的修飾子を削除するための演習として残ります。

わかりました。私の印象では、合計は常に100である必要があり、100を下回ったり上回ったりする必要はありません。したがって、4x20%が最小の場合、最大60%は不可能です。ただし、値は可変であり、別の設定では、最小値が4x10%である場合があり、最大値が60%の場合は理にかなっていることを理解しています。私はその目的のためにコードをテストしませんでした。

ただし、残りの部分から最小値(4 * 20%)を差し引いて分散するため、最終結果を得るにはこれらの値を追加する必要があります。

再帰的分散機能は、終了条件から始まります。最後の要素に到達します。残りの部分(それがいくらになるか)は、この最後の要素に配置する必要があります。

それ以外の場合は、この要素のすべての可能な値を取得し、残りを分散します。

アップデート:

上限を考慮してコードを変更し、片側の例を簡略化しました。これは、3つの要素のみを使用し、100ではなく最大10を使用するためです。出力には、実際の値(最小+可変部分)が表示されます。アルゴリズムは、上限制約に違反しない解のみを追加します。

サンプル出力:

 2 2 6
 2 3 5
 2 4 4
 3 2 5
 3 3 4
 3 4 3
total size of results are 6
于 2012-05-25T20:40:42.990 に答える