組み合わせのリストを繰り返しで貪欲に分割する


10

まず、いくつかの定義:

  • とが与えられた場合nマルチセットkのソートされたリストを検討してください。各マルチセットについて、繰り返しを使用して番号を選択します。k{0, 1, ..., n-1}

たとえば、n=5およびの場合、次のようになりk=3ます。

[(0、0、0)、(0、0、1)、(0、0、2)、(0、0、3)、(0、0、4)、(0、1、1)、( 0、1、2)、(0、1、3)、(0、1、4)、(0、2、2)、(0、2、3)、(0、2、4)、(0、 3、3)、(0、3、4)、(0、4、4)、(1、1、1)、(1、1、2)、(1、1、3)、(1、1、 4)、(1、2、2)、(1、2、3)、(1、2、4)、(1、3、3)、(1、3、4)、(1、4、4) 、(2、2、2)、(2、2、3)、(2、2、4)、(2、3、3)、(2、3、4)、(2、4、4)、( 3、3、3)、(3、3、4)、(3、4、4)、(4、4、4)]

  • 一部は一部のすべてのマルチセットの交差点の大きさは、少なくともある特性を有するマルチセットのリストですk-1。つまり、すべてのマルチセットを受け取り、それらを(マルチセットの交差を使用して)一度に交差させます。例[(1, 2, 2), (1, 2, 3), (1, 2, 4)]として、交差点のサイズが2であるパー​​ツはですが、[(1, 1, 3),(1, 2, 3),(1, 2, 4)]交差点のサイズが1であるため、そうではありません。

仕事

あなたのコードは2つの引数nを取る必要がありkます。次に、これらのマルチセットをソート順に貪欲に調べ、リストの一部を出力します。この場合n=5, k=3、正しいパーティション分割は次のとおりです。

(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 0, 4)
(0, 1, 1), (0, 1, 2), (0, 1, 3), (0, 1, 4)
(0, 2, 2), (0, 2, 3), (0, 2, 4)
(0, 3, 3), (0, 3, 4)
(0, 4, 4)
(1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 1, 4)
(1, 2, 2), (1, 2, 3), (1, 2, 4)
(1, 3, 3), (1, 3, 4)
(1, 4, 4)
(2, 2, 2), (2, 2, 3), (2, 2, 4)
(2, 3, 3), (2, 3, 4)
(2, 4, 4)
(3, 3, 3), (3, 3, 4)
(3, 4, 4), (4, 4, 4)

の別の例を次に示しn = 4, k = 4ます。

(0, 0, 0, 0), (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)
(0, 0, 1, 1), (0, 0, 1, 2), (0, 0, 1, 3)
(0, 0, 2, 2), (0, 0, 2, 3)
(0, 0, 3, 3)
(0, 1, 1, 1), (0, 1, 1, 2), (0, 1, 1, 3)
(0, 1, 2, 2), (0, 1, 2, 3)
(0, 1, 3, 3)
(0, 2, 2, 2), (0, 2, 2, 3)
(0, 2, 3, 3), (0, 3, 3, 3)
(1, 1, 1, 1), (1, 1, 1, 2), (1, 1, 1, 3)
(1, 1, 2, 2), (1, 1, 2, 3)
(1, 1, 3, 3)
(1, 2, 2, 2), (1, 2, 2, 3)
(1, 2, 3, 3), (1, 3, 3, 3)
(2, 2, 2, 2), (2, 2, 2, 3)
(2, 2, 3, 3), (2, 3, 3, 3)
(3, 3, 3, 3)

貪欲の意味の明確化: 各マルチセットについて、既存のパーツに追加できるかどうかを確認します。できれば追加します。できない場合は、新しい部分を開始します。上記の例のように、ソートされた順序でマルチセットを確認します。

出力

パーティションを好きな形式で出力できます。ただし、マルチセットは1行に水平に記述する必要があります。つまり、個々のマルチセットを縦に書いたり、数行にまたがったりしないでください。出力でパーツの表現を分離する方法を選択できます。

仮定

私たちはそれを仮定することができn >= k > 0ます。


@LuisMendo間違えました。マルチセットは1行に水平に書く必要があることを意味しました。

最初のテストケースでは、なぜ(0, 4, 4)それ自体がなぜですか?あなたの説明を与えられれば、私はその「部分」がなると思います(0, 4, 4), (1, 4, 4), (2, 4, 4), (3, 4, 4), (4, 4, 4)(0, 0, 3, 3)2番目のテストケースでも同様です。
グレッグマーティン

@GregMartinメソッドの貪欲さのため。それは一般的に最適ではないというのはあなたの言う通りです。貪欲ではない方法で取得できるパーツの最小数は、難しい質問の場合は興味深いものです

ああ、文字通り、次の用語が「アクティブ」な部分と一致しなくなると、その部分は永久に閉じられます。OK。
グレッグマーティン

回答:


4

ゼリー26 25 バイト

œ&µL‘<⁴ȧ⁹ȯ
œċµç\L€=⁴œṗµḊ’

リストのリストの表現を出力する完全なプログラム。各リストは一部です。たとえば、n = 5、k = 3の場合:

[[[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 0, 3], [0, 0, 4]], [[0, 1, 1], [0, 1, 2], [0, 1, 3], [0, 1, 4]], [[0, 2, 2], [0, 2, 3], [0, 2, 4]], [[0, 3, 3], [0, 3, 4]], [0, 4, 4], [[1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 1, 4]], [[1, 2, 2], [1, 2, 3], [1, 2, 4]], [[1, 3, 3], [1, 3, 4]], [1, 4, 4], [[2, 2, 2], [2, 2, 3], [2, 2, 4]], [[2, 3, 3], [2, 3, 4]], [2, 4, 4], [[3, 3, 3], [3, 3, 4]], [[3, 4, 4], [4, 4, 4]]]

注:表現使用削除し、冗長 [ 及び ] 長さ1のリストの周り。

オンラインでお試しください!またはかなり印刷されたバージョンを見る(コスト3バイト)

どうやって?

œ&µL‘<⁴ȧ⁹ȯ - Link 1, conditional multi-set intersection: list x, list y
œ&         - multi-set intersection(x, y)
  µ        - monadic chain separation (call that i)
   L       - length(i)
    ‘      - increment
     <     - less than?:
      ⁴    -     2nd program input, k
       ȧ   - logical and with:
        ⁹  -     link's right argument, y (y if i is too short, else 0)
         ȯ - logical or (y if i is too short, else i)

œċµç\L€=⁴œṗµḊ’ - Main link: n, k
œċ             - combinations with replacement(n, k) (sorted since n implies [1,n])
  µ            - monadic chain separation (call that w)
         œṗ    - partition w at truthy indexes of:
   ç\          -     reduce w with last link (1) as a dyad
     L€        -     length of €ach
        ⁴      -     2nd program input, k
       =       -     equal (vectorises)
           µ   - monadic chain separation
            Ḋ  - dequeue (since the result will always start with an empty list)
             ’ - decrement (vectorises) (since the Natural numbers were used by œċ)

これは素晴らしい。ありがとうございました。

3

MATLAB、272バイト

function g(n,k);l=unique(sort(nchoosek(repmat(0:n-1,1,k),k),2),'rows');p=zeros(0,k);for i=1:size(l,1)p=[p;l(i,:)];a=0;for j=1:size(p,1)for m=1:size(p,1)b=0;for h=1:k if(p(j,h)==p(m,h))b=b+1;end;end;if(b<k-1)a=1;end;end;end;if(a)fprintf('\n');p=l(i,:);end;disp(l(i,:));end;

出力:

>> g(5,3)
 0     0     0

 0     0     1

 0     0     2

 0     0     3

 0     0     4


 0     1     1

 0     1     2

 0     1     3

 0     1     4


 0     2     2

 0     2     3

 0     2     4


 0     3     3

 0     3     4


 0     4     4


 1     1     1

 1     1     2

 1     1     3

 1     1     4


 1     2     2

 1     2     3

 1     2     4


 1     3     3

 1     3     4


 1     4     4


 2     2     2

 2     2     3

 2     2     4


 2     3     3

 2     3     4


 2     4     4


 3     3     3

 3     3     4


 3     4     4

 4     4     4

>> g(4,4)
 0     0     0     0

 0     0     0     1

 0     0     0     2

 0     0     0     3


 0     0     1     1

 0     0     1     2

 0     0     1     3


 0     0     2     2

 0     0     2     3


 0     0     3     3


 0     1     1     1

 0     1     1     2

 0     1     1     3


 0     1     2     2

 0     1     2     3


 0     1     3     3


 0     2     2     2

 0     2     2     3


 0     2     3     3

 0     3     3     3


 1     1     1     1

 1     1     1     2

 1     1     1     3


 1     1     2     2

 1     1     2     3


 1     1     3     3


 1     2     2     2

 1     2     2     3


 1     2     3     3

 1     3     3     3


 2     2     2     2

 2     2     2     3


 2     2     3     3

 2     3     3     3


 3     3     3     3

異なるパーツ間の2つの空の行。

非ゴルフ:

function g(n,k);
l=unique(sort(nchoosek(repmat(0:n-1,1,k),k),2),'rows');
p=zeros(0,k);
for i=1:size(l,1)
    p=[p;l(i,:)];
    a=0;
    for j=1:size(p,1)
        for m=1:size(p,1)
            b=0;
            for h=1:k
                if(p(j,h)==p(m,h))
                    b=b+1;
                end;
            end;
                if(b<k-1)
                    a=1;
                end;
        end;
    end;
    if(a)
        fprintf('\n');
        p=l(i,:);
    end;
    disp(l(i,:));
end;

説明:

まず、ブルートフォースを持つすべてのマルチセットを見つけます。

l=unique(sort(nchoosek(repmat(0:n-1,1,k),k),2),'rows');

repmat(0:n-1, 1, k)値のベクトルをから0までn-1 k繰り返します。

nchoosek(x, k) 繰り返しベクトルのすべてのk組み合わせを含む行列を返します。

sort(x, 2)すべてのkの組み合わせを並べ替え、unique(x, 'rows')すべての重複を削除します。

p=zeros(0,k);k列を持つ空の行列を作成します。スタックとして使用します。最も外側のforループの各反復で、最初に現在のマルチセットを上記のスタックに追加しますp=[p;l(i,:)];

次に、スタック内のすべてのマルチセットの交差が少なくともk-1次のコードで長いかどうかを確認します(intersectセットを返すため、MATLABのコマンドを使用して交差を確認することはできませんが、マルチセットが必要です)。

a=0;
for j=1:size(p,1)
    for m=1:size(p,1)
        b=0;
        for h=1:k 
            if(p(j,h)==p(m,h))
                b=b+1;
            end;
        end;
        if(b<k-1)
            a=1;
        end;
    end;
end;

さて、交差が十分に長い場合はa == 0、そうでない場合はa == 1

交差が十分に長くない場合は、改行を出力してスタックを空にします。

if(a)
    fprintf('\n');
    p=l(i,:); % Only the current multiset will be left in the stack.
end;

次に、現在のマルチセットを出力します。

disp(l(i,:));

あなたはそれを割ったように見えます!あなたの方法を説明できますか?

@Lembik説明を追加しました。
Steadybox 2017

3

MATL、34バイト

vi:qiZ^!S!Xu!"@!&vt1&dXasq?0&Y)0cb

パーツは空白を含む行で区切られます。

オンラインでお試しください!

説明

免責事項:この方法は機能するようです(テストケースでは機能します)が、常に機能するという証拠はありません

マルチセットは、内部的に(つまり、各マルチセットに非減少エントリがある)と外部的に(つまり、Mが辞書順でNに先行する場合、マルチセットMがマルチセットNの前に来ます)の両方でソートされます。

マルチセットの交差を計算するには、並べ替えられたマルチセットを行列の行として配置し、各列に沿って連続した差を計算します。最大で1つを除くすべての列の差がすべてゼロに等しい場合、マルチセットは同じパーツに属します。

このテストは、のようなマルチセットのための偽陰性の結果を与えるだろう(1,2,3)(2,3,4):場合でも23一般的なエントリです彼らは一致しない列にあるため、彼らのような検出されません。

ただし、少なくともテストケースでは、これは問題にはならないようです。マルチセット等とのテストと思われる1,2,32,3,4、いくつかの中間の多重集合が否定的な結果を与えたので、彼らはすでにさまざまな部分であるため、決して実際には、行う必要があります。これが本当に当てはまる場合、その理由は間違いなくマルチセットがソートされるという事実に関係しています。

ただし、これを証明するものはありません。うまくいくようです。

v           % Concatenate stack vertically: gives an empty array. This will
            % grow into the first part
i:q         % Input n. Push [0 1 ... n-1]
i           % Input k
Z^          % Cartesian power. Each Cartesian tuple is on a row
!S!         % Sort each row
Xu          % Unique rows. This gives all multisets, sorted, each on a row
!           % Transpose
"           % For each column
  @!        %   Push current multiset as a row
  &v        %   Vertically concatenate with the part so far
  t         %   Duplicate
  1&d       %   Consecutive differences along each column
  Xas       %   Number of columns that contain at least one non-zero entry
  q?        %   If that number is not 1 (this means that the current 
            %   multiset should begin a new part)
    0&Y)    %     Push last row, then the array with the remaining rows.
            %     Said array is a part, which we now know is complete
    0c      %     Push character 0. This will be shown as a line containing 
            %     a space. This is used as a separator between parts.
    b       %     Bubble up. This moves the loose row to the top. This row 
            %     is the beginning of a new part
            %   Implicitly end if
            % Implicitly end for
            % Implicitly display

とても印象的です。

あなたが説明する方法が常に機能するかどうかを理解しようとしています。私は中にその中に見n=k=4我々はで新しい部品のスタートを持っている場合(0, 0, 3, 3)、そのベクトル化の連続違い、前のマルチセットを(0, 0, 2, 3)ので、どのように「の部分は、これまでのところ、」この作品を作るん、唯一の違いがありますか?(または同等に、代わりに使用された前のステップの結果は何でした(0, 0, 2, 3)か?)
ジョナサンアラン

ああ、私はあなたが連続した違いを実行するのを見ます。はい、これは常に動作するはずです!複数のアイテムが変化するポイントを文字通り探していますが、マルチセットの交差ではなく、単にベクトル化された交差です。これは、マルチセットが最初にソートされるため機能します。
ジョナサンアラン

@JonathanAllanはい、それは交差ではなく連続的な違いです。私はそれが常にうまくいくことをまだはっきりと見ていませんが、あなたがそう言うなら... :-)
ルイスメンド

1

PHP、245バイト

for(;$i<($n=$argv[1])**$m=$argv[2];$i++){for($a=[],$v=$i;$v|count($a)<$m;$v=$v/$n^0)array_unshift($a,$v%$n);sort($a);in_array($a,$r)?:$r[]=$a;}foreach($r as$k=>$v)$k&&count(array_diff_assoc($x[$c][0],$v))<2?$x[$c][]=$v:$x[++$c][]=$v;print_r($x);

オンラインでお試しください!

拡張

for(;$i<($n=$argv[1])**$m=$argv[2];$i++){ # loop till $argv[1]**$argv[2]
    for($a=[],$v=$i;$v|count($a)<$m;$v=$v/$n^0) 
    array_unshift($a,$v%$n); # create base n array
    sort($a); #sort array
    in_array($a,$r)?:$r[]=$a; # if sorted array is not in result add it
}    
foreach($r as$k=>$v)
    $k&& # > first item and
    count(array_diff_assoc($x[$c][0],$v))<2 # if difference is only 1 item between actual item and first item in last storage item
    ?$x[$c][]=$v # add item in last storage array
    :$x[++$c][]=$v; # make a new last storage array
print_r($x); # Output as array

文字列として出力

foreach($x as$y){$p=[];
foreach($y as$z){$p[]=$o="(".join(",",$z).")";}
    echo join(", ",$p)."\n";
}

より精度を高めるにはn> 15

for($i=0;$i<bcpow($argv[1],$argv[2]);$i=bcadd($i,1)){
    for($a=[],$v=$i;$v|count($a)<$argv[2];$v=bcdiv($v,$argv[1]))
    array_unshift($a,bcmod($v,$argv[1]));
    sort($a);
    in_array($a,$r)?:$r[]=$a;
}

これは動作するようです!しかし、より精度が高いとはどういう意味ですか?

@Lembikショートバージョンが戻っています0ため(16**16-1)%16だけのために必要とされる精度でロングバージョン作業がn>15 bcmod(bcsub(bcpow(16,16),1),16)ある15 php.net/manual/en/ref.bc.php
イェルクHülsermann
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.