1

すべてのサブセット合計トピックを読みましたが、次の問題のアルゴリズムの実装にまだ問題があります。

N 個の整数 (N<=20) の配列 A が与えられた場合、

  • a[i]<=20
  • 値は一意である必要はありません

および整数 K (K<=20)。

ルール:

  • K に等しい配列項目は、K で「カバー」されます。
  • 2 つ以上の配列番号の合計が K に等しい場合、これらの番号もカバーされます。
  • 配列内の各数値は 1 回だけカバーできます。

N=6、整数: 1、1、2、3、4、5

K=4

可能なカバレッジ:

  1. カバレッジ
    • 4がカバーされています。
    • 1、1、2 は 1+1+2=4 としてカバーされます。
  2. カバレッジ
    • 4がカバーされています。
    • 1、3は1+3=4としてカバーされます。

K=5

可能なカバレッジ:

  1. カバレッジ
    • 5がカバーされています。
    • 1,1,3 は 1+1+3=5 としてカバーされます。
  2. カバレッジ
    • 5がカバーされています。
    • 1,4 は 1+4=5 としてカバーされます。
    • 2,3 は 2+3=5 としてカバーされます。

ゴール:

与えられた配列 A と整数 K について、可能なすべての「カバレッジ」を見つけます。ほとんどの配列アイテムをカバーするものだけでなく、すべてのカバレッジが必要です。

私は2つのアプローチで試しました:

  1. 総当たりアルゴリズム。可能なすべてのサイズのすべての可能なサブセットをチェックすることは機能しますが、10 個の数だけでも時間がかかりすぎます。500ミリ秒以内に完了する必要があります。
  2. まず、配列を降順にソートしました。次に、サブサムの可能な数ごとに「スロット」を作成します。配列をループして、次のようなルールに従ってスロットに数字を入れます。
    • その合計が K に等しくなった場合、番号をスロットに入れます。
    • すべてのスロットの合計が最小のスロットに数字を入れます。
    • すべてのスロットの K に最も近い合計を与えるスロットに数値を入力します。

2 番目のアプローチは機能し、高速に動作します。しかし、一部のカバレッジが見つからないシナリオを見つけました。

誰かがこの問題を解決するためのアイデアを提供してくれれば幸いです。

問題をうまく説明できれば幸いです。

ありがとう。

4

2 に答える 2

1

私はそれに対する答えを用意していませんが、ここで役に立つかもしれない「ビンパッキングの問題」を調べることをお勧めします。

主な問題は、数 K を与えるすべての可能な合計を見つけることです。

Collection All_Possible_Sums_GivingK;

find_All_Sums_Equal_To_K(Integer K, Array A)
{
    /* this function after finding result
    add it to global Collection AllPossibleSumsGivingK; */
    find_All_Elements_Equal_To_K(Integer K, Array A); 

    Array B = Remove_Elements_Geater_Or_Equal_To_K(Integer K, Array A);

    for all a in A {
        find_All_Sums_Equal_To_K(Integer K-a, Array B-a) 
    }
} 
于 2012-05-30T21:59:31.207 に答える
0

私はこれを、別のサブセット和バリアントに与えた以前の回答から変更しました:https ://stackoverflow.com/a/10612601/120169

ここでは、上記の番号のK = 8のケースで実行しています。ここでは、2つの「カバレッジ」の1つに2つの異なる場所で1を再利用しています。それがあなたのためにどのように機能するか教えてください。

public class TurboAdder2 {
    // Problem inputs
    // The unique values
    private static final int[] data = new int[] { 1, 2, 3, 4, 5 };
    // counts[i] = the number of copies of i
    private static final int[] counts = new int[] { 2, 1, 1, 1, 1 };
    // The sum we want to achieve
    private static int target = 8;

    private static class Node {
        public final int index;
        public final int count;
        public final Node prevInList;
        public final int prevSum;
        public Node(int index, int count, Node prevInList, int prevSum) {
            this.index = index;
            this.count = count;
            this.prevInList = prevInList;
            this.prevSum = prevSum;
        }
    }

    private static Node sums[] = new Node[target+1];

    // Only for use by printString and isSolvable.
    private static int forbiddenValues[] = new int[data.length];

    private static boolean isSolvable(Node n) {
        if (n == null) {
            return true;
        } else {
            while (n != null) {
                int idx = n.index;
                // We prevent recursion on a value already seen.
                // Don't use any indexes smaller than lastIdx
                if (forbiddenValues[idx] + n.count <= counts[idx]) {
                    // Verify that none of the bigger indexes are set
                    forbiddenValues[idx] += n.count;
                    boolean ret = isSolvable(sums[n.prevSum]);
                    forbiddenValues[idx] -= n.count;
                    if (ret) {
                        return true;
                    }
                }
                n = n.prevInList;
            }
            return false;
        }
    }

    public static void printString(String prev, Node n, int firstIdx, int lastIdx) {
        if (n == null) {
            printString(prev +" |", sums[target], -1, firstIdx);
        } else {
            if (firstIdx == -1 && !isSolvable(sums[target])) {
                int lidx = prev.lastIndexOf("|");
                if (lidx != -1) {
                    System.out.println(prev.substring(0, lidx));
                }
            }
            else {
                while (n != null) {
                    int idx = n.index;
                    // We prevent recursion on a value already seen.
                    // Don't use any indexes larger than lastIdx
                    if (forbiddenValues[idx] + n.count <= counts[idx] && (lastIdx < 0 || idx < lastIdx)) {
                        // Verify that none of the bigger indexes are set
                        forbiddenValues[idx] += n.count;
                        printString((prev == null ? "" : (prev + (prev.charAt(prev.length()-1) == '|' ? " " : " + ")))+data[idx]+"*"+n.count, sums[n.prevSum], (firstIdx == -1 ? idx : firstIdx), idx);
                        forbiddenValues[idx] -= n.count;
                    }
                    n = n.prevInList;
                }
            }
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < data.length; i++) {
            int value = data[i];
            for (int count = 1, sum = value; count <= counts[i] && sum <= target; count++, sum += value) {
                for (int newsum = sum+1; newsum <= target; newsum++) {
                    if (sums[newsum - sum] != null) {
                        sums[newsum] = new Node(i, count, sums[newsum], newsum - sum);
                    }
                }
            }
            for (int count = 1, sum = value; count <= counts[i] && sum <= target; count++, sum += value) {
                sums[sum] = new Node(i, count, sums[sum], 0);
            }
        }
        printString(null, sums[target], -1, -1);
    }
}
于 2012-05-31T07:14:15.047 に答える