L[0]からL[N-1]の昇順でソートされたN個の正の数のリストがあります。
M 個の個別のリスト要素 (置換なし、順序は重要ではない) のサブセット (1 <= M <= N) を、部分和に従って並べ替えて繰り返し処理したいと考えています。M は固定されていません。最終結果では、すべての可能なサブセットを考慮する必要があります。
K 個の最小のサブセットのみを効率的に使用したい (理想的には K の多項式)。M <= K ですべてのサブセットを列挙する明白なアルゴリズムは O(K!) です。
K 個のイテレータ (1 <= M <= K) を最小ヒープに配置し、マスター イテレータをヒープ ルートで動作させることにより、問題を固定サイズ M のサブセットに減らすことができます。
基本的に、Python 関数呼び出しが必要です。
sorted(itertools.combinations(L, M), key=sum)[:K]
...しかし効率的 (N ~ 200、K ~ 30)、1 秒以内に実行する必要があります。
例:
L = [1, 2, 5, 10, 11]
K = 8
answer = [(1,), (2,), (1,2), (5,), (1,5), (2,5), (1,2,5), (10,)]
答え:
David の答えが示すように、重要なトリックは、サブセット S を出力するには、S のすべてのサブセット、特に 1 つの要素のみが削除されたサブセットが以前に出力されている必要があるということです。したがって、サブセットを出力するたびに、このサブセットのすべての 1 要素拡張を追加して検討することができます (最大 K)。それでも、次に出力されるサブセットが、これまでに検討されたすべてのサブセットのリストにあることを確認してください。点。
完全に機能する、より効率的な Python 関数:
def sorted_subsets(L, K):
candidates = [(L[i], (i,)) for i in xrange(min(len(L), K))]
for j in xrange(K):
new = candidates.pop(0)
yield tuple(L[i] for i in new[1])
new_candidates = [(L[i] + new[0], (i,) + new[1]) for i in xrange(new[1][0])]
candidates = sorted(candidates + new_candidates)[:K-j-1]
UPDATE、O(K log K) アルゴリズムを見つけました。
これは上記のトリックに似ていますが、サブセットの最大値を超える要素が追加されたすべての 1 要素拡張を追加する代わりに、2 つの拡張のみを考慮します。1 つは max(S)+1 を追加し、もう 1 つはmax(S) を max(S) + 1 にシフトします (これにより、最終的にすべての 1 要素拡張が右側に生成されます)。
import heapq
def sorted_subsets_faster(L, K):
candidates = [(L[0], (0,))]
for j in xrange(K):
new = heapq.heappop(candidates)
yield tuple(L[i] for i in new[1])
i = new[1][-1]
if i+1 < len(L):
heapq.heappush(candidates, (new[0] + L[i+1], new[1] + (i+1,)))
heapq.heappush(candidates, (new[0] - L[i] + L[i+1], new[1][:-1] + (i+1,)))
私のベンチマークから、K のすべての値で高速です。
また、事前に K の値を指定する必要はありません。アルゴリズムの効率を変えることなく、いつでも反復して停止することができます。また、候補の数は K+1 で制限されることに注意してください。
プライオリティキューの代わりにプライオリティ デキュー (min-max ヒープ)を使用することで、さらに改善できる可能性がありますが、率直に言って、このソリューションには満足しています。ただし、線形アルゴリズム、またはそれが不可能であることの証明に興味があります。