반복적으로 조합 목록을 탐욕스럽게 분할하십시오.


10

먼저 몇 가지 정의가 있습니다.

  • 주어진 nand k, 정렬 된 다중 집합 목록을 고려하십시오. 각 다중 집합에 대해 반복과 함께 k숫자를 선택 합니다 {0, 1, ..., n-1}.

예를 들어 for n=5k=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이기 때문에 그렇지 않습니다.

직무

코드는 두 개의 인수를해야 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)

욕심의 의미에 대한 설명 : 각 다중 집합에 대해 기존 부분에 추가 할 수 있는지 확인합니다. 가능하다면 추가 할 수 있습니다. 그것이 우리가 새로운 부분을 시작할 수 없다면. 우리는 위에서 주어진 예제에서와 같이 멀티 세트를 정렬 된 순서로 봅니다.

산출

원하는 형식으로 분할을 출력 할 수 있습니다. 그러나 멀티 세트는 한 줄에 가로로 써야합니다. 즉, 개별 다중 집합을 세로로 쓰거나 여러 줄에 걸쳐서는 ​​안됩니다. 출력에서 부품 표현을 분리하는 방법을 선택할 수 있습니다.

가정

우리는 그것을 가정 할 수 있습니다 n >= k > 0.


@LuisMendo 방금 실수했습니다. 멀티 세트는 한 줄에 가로로 써야한다는 의미였습니다.

첫 번째 테스트 사례에서 왜 (0, 4, 4)그 자체입니까? 당신의 설명을 감안할 때, 나는 그 "부분"이 될 것이라고 생각합니다 (0, 4, 4), (1, 4, 4), (2, 4, 4), (3, 4, 4), (4, 4, 4). (0, 0, 3, 3)두 번째 테스트 사례와 유사합니다 .
Greg Martin

이 방법의 탐욕 때문에 @GregMartin. 일반적으로 차선책 일 것입니다. 욕심없는 방법으로 얻을 수있는 최소한의 부품 수는 흥미로운 질문이라면 흥미 롭습니다.

아, 당신은 말 그대로 다음 번의 용어가 "활성"부분과 일치하지 않으면 그 부분은 영원히 닫힙니다. 확인.
Greg Martin

답변:


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

다른 부분 사이에 두 개의 빈 줄이 있습니다.

언 골프 드 :

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

3

MATL , 34 바이트

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

공백이 포함 된 선으로 부품이 분리됩니다.

온라인으로 사용해보십시오!

설명

면책 조항 :이 방법은 효과가있는 것으로 보이지만 (테스트 경우와 동일) 항상 작동한다는 증거는 없습니다

멀티 세트 (즉 MULTISET 외부 적, 내부적으로 (즉, 각 MULTISET 비 감소했다 항목) 분류되며, M은 MULTISET 앞에 오는 N 경우 M의 선행 N 사전 식).

다중 집합 교집합을 계산하기 위해 정렬 된 다중 집합이 행렬의 행으로 배열되고 각 열을 따라 연속적인 차이가 계산됩니다. 최대 하나를 제외한 모든 열의 차이가 모두 0 인 경우 다중 집합은 동일한 부분에 속합니다.

이 테스트는 같은 멀티 세트에 대한 허위 부정적인 결과를 줄 것 (1,2,3)등을 (2,3,4): 경우에도 2, 3공통 항목, 그들은이 일치하지 않는 컬럼에 있기 때문에 그들은 같은 감지되지 않습니다.

그러나 이것은 적어도 테스트 사례에서 문제가되지 않는 것 같습니다. 이 같은 멀티 세트와 테스트 나타납니다 1,2,32,3,4일부 중간 MULTISET가 부정적인 결과를주고, 그래서 그들은 이미 다른 부분에 있기 때문에 결코 사실이 수행되어야한다. 이것이 사실이라면, 그 이유는 다중 집합이 정렬되어 있다는 사실과 의심의 여지가 없습니다.

그러나 이것에 대한 증거는 없습니다. 그냥 작동하는 것 같습니다.

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)? 대신에 사용 된 이전 단계 결과는 무엇입니까?)
Jonathan Allan

아, 난 당신이 연속적인 차이를 수행 참조하십시오. 예, 항상 작동합니다! 문자 그대로 둘 이상의 항목이 변경되는 지점을 찾고 있지만 다중 집합 교차로가 아니라 단순히 벡터화 된 교차로가 필요합니다. 이는 다중 집합이 시작되도록 정렬 된 이후 작동합니다.
Jonathan Allan

@JonathanAllan 네, 교차점보다는 연속적인 차이입니다. 나는 그것이 항상 작동 할 것이라는 점을 여전히 명확하게 보지 못하지만, 그렇게 말한다면 ... :-)
Luis Mendo

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.