すべてのベクトルパーティションを効率的に生成する


12

ベクトルパーティションは、ベクトルを一連のベクトルに分割し、合計が元になるようにします。パーティションは次のとおりです。

[3, 1, 2] = [3, 1, 2]
[3, 1, 2] = [0, 0, 1] + [0, 0, 1] + [0, 1, 0] + [1, 0, 0] + [2, 0, 0]
[3, 1, 2] = [1, 1, 2] + [2, 0, 0]

ここで、ベクトルの追加は要素ごとに行われます。有効なパーティションには、負の整数を持つベクトル、またはすべてゼロのベクトルは含まれません。

ここでの課題は、ターゲットベクトルが与えられたすべての可能なベクトルパーティションを生成するプログラムまたは関数を記述することです。これは比較的簡単に聞こえるかもしれません...

...しかし、ねじれがあります。入力ベクトルのサイズがLで、生成する最大パーティションの要素がM個の場合、O(L * M)を超えるメモリは使用できません。

整数がO(1)メモリを使用すると仮定できます。つまり、パーティションを生成するときに出力する必要があります。さらに、各パーティションを1回だけ出力する必要があります。たとえば、これらは同じパーティションです。

[3, 1, 2] = [3, 0, 2] + [0, 1, 0]
[3, 1, 2] = [0, 1, 0] + [3, 0, 2]

両方を出力する場合、答えは無効です。


のすべてのパーティション[3, 2]

[3, 2]
[0, 1] + [3, 1]
[0, 1] + [0, 1] + [3, 0]
[0, 1] + [0, 1] + [1, 0] + [2, 0]
[0, 1] + [0, 1] + [1, 0] + [1, 0] + [1, 0]
[0, 1] + [1, 0] + [2, 1]
[0, 1] + [1, 0] + [1, 0] + [1, 1]
[0, 1] + [1, 1] + [2, 0]
[0, 2] + [3, 0]
[0, 2] + [1, 0] + [2, 0]
[0, 2] + [1, 0] + [1, 0] + [1, 0]
[1, 0] + [2, 2]
[1, 0] + [1, 0] + [1, 2]
[1, 0] + [1, 1] + [1, 1]
[1, 1] + [2, 1]
[1, 2] + [2, 0]

答えをテストするには、で実行してください[3, 2, 5, 2]。17939パーティションを生成する必要があります。合計は[3, 2, 5, 2]であり、すべて一意です(最初に各パーティションを辞書式に並べ替えることで一意性をテストできます)。


バイト単位の最短コードが優先されます。

回答:


3

Python 2、289バイト

単純なブルートフォースアルゴリズム。リスト全体を基数max(input)+1b)の数値として扱い、範囲内の各「数値」をチェックして次のこと[0, b**(L*M))を確認します。

  1. 正しい金額まで合計する
  2. アルファベット順です(一意性を保証します)

リストがこれらの基準に一致する場合、プログラムはすべてゼロのベクトルをすべて削除してリストを出力します。

メモリ使用量

このプログラムで使用する最大のデータ構造は、二重にネストされたリストです。リストの長MLには、O(L*M)メモリを提供するためのlissの長さが含まれます。

他のデータ構造では、3つのグローバルint O(3)、1つのリスト長LO(L))、1つの配列長MO(M))、および出力時の最大配列のコピー(O(L*M))があります。

合計すると、これによりメモリ使用量がO(2*L*M + L + M + 3)簡単にO(L*M)なり、基準が満たされます。

時間の複雑さ

ブルートフォースアルゴリズムであるため、このアルゴリズムは非常に低速です。whileループを終了するには、配列の最後のintがである必要がありますb-1b**(L*M)それが起こる前に、ループを実行する必要があります。

さらに、リストを実行するたびに、両方の条件をチェックし、L*M+L+M反復を使用して最悪の場合にリストを印刷する必要があります。これにより、全体的なO(L*M * b**(L*M))。私はプログラムをでテストしようとし[3, 2, 5, 2]ましたが、45分後にあきらめました。

ゴルフプログラム

v=input()
L=len(v)
M=sum(v)
b=max(v)
R=range
t=[L*[0]for i in R(M)]
def A(l,i):
 if i<L*M-1and~-b<l[i/L][i%L]:A(l,i+1)
 l[i/L][i%L]=-~l[i/L][i%L]%-~b
while t[-1][-1]<b:
 if v==[sum(q[i]for q in t)for i in R(L)]and all(`t[i]`>=`t[i+1]`for i in R(M-1)):print[x for x in t if[0]*L!=x]
 A(t,0)

私はこれをもう少しゴルフすることができるかもしれません、特に増分部分。未ゴルフのコードが来る。


この質問を投稿したとき、私が期待していた効率性は間違いありませんが、技術的には問題を解決できると思います:)
orlp
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.