Tekrarlı kombinasyonların listesini açgözlü bir şekilde bölümleyin


10

İlk olarak, birkaç tanım:

  • Verilen nve kbir sıralı liste, düşünün MULTISETS her multiset için seçtiğimiz, knumaraları {0, 1, ..., n-1}tekrarlar ile.

Örneğin, n=5ve k=3için:

[(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)]

  • Bir parça , parçadaki tüm çoklu setlerin kesişme boyutunun en azından bir özelliğe sahip bir çoklu ağlar listesidir k-1. Bu, tüm çoklu kümeleri alır ve aynı anda (çoklu küme kesişimini kullanarak) kesişiriz. Örnek [(1, 2, 2), (1, 2, 3), (1, 2, 4)]olarak, kesişimi 2 büyüklüğünde olduğu için bir parçasıdır, ancak [(1, 1, 3),(1, 2, 3),(1, 2, 4)]değildir, çünkü kesişimi 1 büyüklüğündedir.

Görev

Kodunuz iki argüman almalı nve k. Daha sonra açgözlülükle bu multisets sıralı sırayla gitmek ve listenin bölümlerini çıktı gerekir. Durum n=5, k=3için doğru bölümleme:

(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)

İşte için başka bir örnek 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)

Açgözlülüğün ne anlama geldiğinin açıklığa kavuşturulması : Her bir çoklu set için, bunun mevcut parçaya eklenip eklenemeyeceğini görüyoruz. Olabilirse ekleyebiliriz. Eğer yapamazsa yeni bir parçaya başlarız. Çoklu setlere yukarıda verilen örnekte olduğu gibi sıralı bir şekilde bakarız.

Çıktı

Bölümlemeyi istediğiniz herhangi bir biçimde biçimlendirebilirsiniz. Ancak, çoklu setler tek bir satıra yatay olarak yazılmalıdır. Bireysel bir çoklu set dikey olarak yazılmamalı veya birkaç satıra yayılmamalıdır. Çıktıdaki parçaların sunumunu nasıl ayıracağınızı seçebilirsiniz.

Varsayımlar

Bunu varsayabiliriz n >= k > 0.


@LuisMendo Sadece bir hata yaptım. Yani, çoklu setler tek bir satıra yatay olarak yazılmalıdır.

İlk test durumunda, neden tek (0, 4, 4)başına? Açıklamanız göz önüne alındığında, onun "parçası" olacağını düşünürdüm (0, 4, 4), (1, 4, 4), (2, 4, 4), (3, 4, 4), (4, 4, 4). Benzer şekilde (0, 0, 3, 3)ikinci test durumunda.
Greg Martin

@GregMartin Yöntemin açgözlülüğü nedeniyle. Genel olarak yetersiz olacağına haklısın. Açgözlü olmayan bir yöntemle alabileceğiniz en az sayıda parça zor bir soru ise ilginçtir,

Oh, kelimenin tam anlamıyla, bir sonraki terim "aktif" bölümle eşleşmediğinde, o bölüm sonsuza kadar kapalı demektir. Tamam.
Greg Martin

Yanıtlar:


4

Jöle , 26 25 bayt

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

Her listenin bir parçası olduğu, bir liste listesinin temsilini basan tam program, örneğin n = 5, k = 3 için:

[[[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]]]

Not: kullanılan gösterim , uzunluk 1 [ ve gereksiz listeleri kaldırır ] .

Çevrimiçi deneyin! veya güzel bir baskı sürümünü görün (3 bayt maliyeti)

Nasıl?

œ&µ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 œċ)

Bu harika. Teşekkür ederim.

3

MATLAB, 272 bayt

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;

Çıktı:

>> 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

Farklı parçalar arasında iki boş satır.

Ungolfed:

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;

Açıklama:

İlk önce kaba kuvvetli tüm çoklu setleri buluyoruz:

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

repmat(0:n-1, 1, k)değerlerin vektör tekrar 0için n-1 kkat.

nchoosek(x, k) tekrarlanan vektörün tüm k kombinasyonlarını içeren bir matris döndürür.

sort(x, 2)tüm k kombinasyonlarını sıralar ve ardından unique(x, 'rows')tüm kopyaları kaldırır.

p=zeros(0,k);ksütunlarla boş bir matris oluşturur . Bunu yığın olarak kullanacağız. Outernmost her tekrarında üzerinde fordöngü, ilk bahsedilen istif mevcut MultiSet ekleyin: p=[p;l(i,:)];.

Ardından, yığındaki tüm çoklu ağların kesişiminin en az k-1aşağıdaki kodla uzun olup olmadığını intersectkontrol ederiz (kavşakları kontrol etmek için MATLAB komutunu kullanamayız , çünkü bir küme döndürür, ancak bir çoklu kümeye ihtiyacımız vardır):

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;

Şimdi, kavşak yeterince uzunsa a == 0, aksi takdirde a == 1.

Kavşak yeterince uzun değilse, bir satırsonu yazdırır ve yığını boşaltırız:

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

Sonra sadece mevcut çoklu seti yazdırıyoruz:

disp(l(i,:));

Çatlamış gibisin! Yönteminizi açıklar mısınız?

@Lembik Bir açıklama ekledim.
Steadybox

3

MATL , 34 bayt

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

Parçalar boşluk içeren bir çizgi ile ayrılır.

Çevrimiçi deneyin!

açıklama

Feragatname: Bu yöntem işe yarıyor gibi görünüyor (ve test senaryolarında var), ancak her zaman yaptığına dair bir kanıtım yok

MULTISETS (yani multiset dıştan hem içten (yani her multiset olmayan azalan bir kayıtlar) sıralanır ve M multiset önce gelir N ise M önce gelir , N sözlük sırasında).

Çok kümeli kesişimin hesaplanması için, sıralı çok kümeler bir matrisin satırları olarak düzenlenir ve her sütun boyunca ardışık farklılıklar hesaplanır. Birden fazla hariç tüm sütunların sıfıra eşit tüm farklılıkları varsa, çoklu ayarlar aynı kısma aittir.

Bu test, (1,2,3)ve gibi çoklu kümeler için yanlış negatif sonuç verir (2,3,4):: ortak girişler olsalar bile 2, 3eşleşmeyen sütunlarda oldukları için bu şekilde algılanmazlar.

Bununla birlikte, en azından test vakalarında bu bir sorun gibi görünmemektedir. Görünüşe göre, çoklu aralıklar arasında bir test yapılmalı 1,2,3ve 2,3,4aslında hiçbir zaman yapılmamalıdır, çünkü bazı ara çoklu ayarlar olumsuz bir sonuç vermiştir ve bu yüzden zaten farklı bölümlerde bulunmaktadırlar. Bu gerçekten doğruysa, şüphe yok ki, çoklu setlerin sıralandığı gerçeği ile ilgilidir.

Yine de bunun bir kanıtı yok. Sadece işe yarıyor gibi görünüyor.

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

Çok etkileyici.

Açıkladığınız yöntemin her zaman işe yarayıp yaramayacağını anlamaya çalışıyorum. Görüyorum ki, n=k=4yeni bir parçamızın başlaması durumunda (0, 0, 3, 3), bunun art arda vektörize edilmiş farkı ve önceki çoklu küme, (0, 0, 2, 3)sadece bir fark var, öyleyse "şimdiye kadar" bu işi nasıl yapıyor? (veya eşdeğer olarak yerine kullanılan önceki adım sonucu (0, 0, 2, 3)neydi?)
Jonathan Allan

Ah, ard arda bir fark yarattığını görüyorum. Evet bu her zaman işe yarar! Kelimenin tam anlamıyla birden fazla öğenin değiştiği noktaları arıyorsunuz, ancak çoklu setli kavşak yerine, basitçe vektörleştirilmiş kavşak - mutli-kümeleri başlangıç ​​olarak sıralandığı için çalışacak.
Jonathan Allan

@JonathanAllan Evet, kavşak yerine ardışık fark. Hala her zaman işe yarayacağını net görmüyorum, ama öyle diyorsan ... :-)
Luis Mendo

1

PHP, 245 Bayt

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);

Çevrimiçi deneyin!

Expanded

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

Dize Olarak Çıktı

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

Daha fazla hassasiyet için 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;
}

Bu işe yarıyor gibi görünüyor! Peki daha kesin olarak ne demek istiyorsun?

@Lembik kısa versiyon geri verir 0için (16**16-1)%16ve yalnızca gerekli olan hassasiyet ile uzun versiyon çalışma n>15 bcmod(bcsub(bcpow(16,16),1),16)olduğunu 15 php.net/manual/en/ref.bc.php
Jörg Hülsermann
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.