Tham lam phân vùng danh sách kết hợp với sự lặp lại


10

Đầu tiên, một vài định nghĩa:

  • Đưa ra nk, xem xét danh sách các multiset được sắp xếp , trong đó với mỗi multiset, chúng tôi chọn các ksố từ {0, 1, ..., n-1}lặp lại.

Ví dụ: cho n=5k=3, chúng tôi có:

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

  • Một phần là một danh sách các multisets với thuộc tính rằng kích thước của giao điểm của tất cả các multiset trong phần đó là ít nhất k-1. Đó là chúng ta lấy tất cả các multiset và cắt chúng (sử dụng giao điểm multiset) cùng một lúc. Ví dụ, [(1, 2, 2), (1, 2, 3), (1, 2, 4)]là một phần vì giao điểm của nó có kích thước 2, nhưng [(1, 1, 3),(1, 2, 3),(1, 2, 4)]không phải, bởi vì giao điểm của nó có kích thước 1.

Bài tập

Mã của bạn nên có hai đối số nk. Sau đó, nó nên tham lam đi qua các multisets theo thứ tự được sắp xếp và xuất ra các phần của danh sách. Đối với trường hợp n=5, k=3, phân vùng chính xác là:

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

Đây là một ví dụ khác cho 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)

Làm rõ ý nghĩa của sự tham lam: Đối với mỗi multiset, chúng ta sẽ xem liệu nó có thể được thêm vào phần hiện có hay không. Nếu nó có thể chúng ta thêm nó. Nếu nó không thể chúng ta bắt đầu một phần mới. Chúng tôi xem xét các multisets theo thứ tự được sắp xếp như trong ví dụ được đưa ra ở trên.

Đầu ra

Bạn có thể xuất phân vùng theo bất kỳ định dạng hợp lý nào bạn muốn. Tuy nhiên, nhiều trang nên được viết theo chiều ngang trên một dòng. Đó là một multiset cá nhân không nên được viết theo chiều dọc hoặc trải rộng trên một số dòng. Bạn có thể chọn cách bạn phân tách đại diện của các bộ phận trong đầu ra.

Giả định

Chúng ta có thể giả định rằng n >= k > 0.


@LuisMendo Tôi vừa mắc lỗi. Tôi có nghĩa là nhiều trang nên được viết theo chiều ngang trên một dòng.

Trong trường hợp thử nghiệm đầu tiên, tại sao lại là (0, 4, 4)chính nó? Đưa ra mô tả của bạn, tôi sẽ nghĩ rằng "phần" của nó sẽ là (0, 4, 4), (1, 4, 4), (2, 4, 4), (3, 4, 4), (4, 4, 4). Tương tự như vậy (0, 0, 3, 3)trong trường hợp thử nghiệm thứ hai.
Greg Martin

@GregMartin Vì sự tham lam của phương pháp. Bạn nói đúng rằng nó sẽ không tối ưu. Số lượng phần tối thiểu bạn có thể nhận được bằng phương pháp không tham lam là một câu hỏi thú vị nếu khó,

Ồ, bạn có nghĩa đen là một khi thuật ngữ tiếp theo không khớp với phần "hoạt động", thì phần đó sẽ bị đóng vĩnh viễn. Đồng ý.
Greg Martin

Câu trả lời:


4

Thạch , 26 25 byte

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

Chương trình đầy đủ in đại diện cho một danh sách các danh sách, mỗi danh sách là một phần, ví dụ: 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]]]

Lưu ý: biểu diễn được sử dụng sẽ loại bỏ các phần thừa [ ] xung quanh danh sách có độ dài 1.

Hãy thử trực tuyến! hoặc xem phiên bản in đẹp (giá 3 byte)

Làm sao?

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

Điều đó thật tuyệt. Cảm ơn bạn.

3

MATLAB, 272 byte

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;

Đầu ra:

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

Hai dòng trống giữa các phần khác nhau.

Ung dung:

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;

Giải trình:

Đầu tiên chúng tôi tìm thấy tất cả các multisets với lực lượng vũ phu:

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

repmat(0:n-1, 1, k)lặp đi lặp lại các vector của các giá trị từ 0để n-1 klần.

nchoosek(x, k) trả về một ma trận chứa tất cả các kết hợp k của vectơ lặp lại.

sort(x, 2)sắp xếp tất cả các kết hợp k, và sau đó unique(x, 'rows')loại bỏ tất cả các bản sao.

p=zeros(0,k);tạo một ma trận rỗng với kcác cột. Chúng tôi sẽ sử dụng nó như một chồng. Trên mỗi lần lặp của forvòng lặp ngoài cùng, trước tiên chúng ta thêm multiset hiện tại vào ngăn xếp đã nói : p=[p;l(i,:)];.

Sau đó, chúng tôi kiểm tra xem giao điểm của tất cả các multiset trong ngăn xếp có k-1dài ít nhất với mã sau không (chúng tôi không thể sử dụng intersectlệnh MATLAB để kiểm tra các giao điểm, bởi vì nó trả về một tập hợp, nhưng chúng tôi cần một multiset):

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;

Bây giờ, nếu giao lộ đủ dài a == 0, nếu không a == 1.

Nếu giao lộ không đủ dài, chúng tôi sẽ in một dòng mới và làm trống ngăn xếp:

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

Sau đó, chúng tôi chỉ cần in nhiều trang hiện tại:

disp(l(i,:));

Hình như bạn đã bẻ khóa nó! Bạn có thể giải thích phương pháp của bạn?

@Lembik Tôi thêm một lời giải thích.
Steadybox

3

MATL , 34 byte

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

Các bộ phận được phân tách bằng một dòng chứa khoảng trắng.

Hãy thử trực tuyến!

Giải trình

Tuyên bố miễn trừ trách nhiệm: phương pháp này dường như hoạt động (và nó thực hiện trong các trường hợp thử nghiệm), nhưng tôi không có bằng chứng rằng nó luôn luôn làm

Multiset được sắp xếp, cả bên trong (tức là mỗi multiset có các mục không giảm) và bên ngoài (tức là multiset M đi trước multiset N nếu M đi trước N từ vựng).

Để tính toán giao điểm nhiều trang, các đa phân loại được sắp xếp được sắp xếp thành các hàng của ma trận và các khác biệt liên tiếp được tính dọc theo mỗi cột. Nếu tất cả các cột ngoại trừ tối đa một cột có tất cả các khác biệt bằng 0, thì các đa thuộc về cùng một phần.

Thử nghiệm này sẽ cho kết quả âm tính giả đối với nhiều trang như (1,2,3)(2,3,4): ngay cả khi 2, 3là các mục chung, chúng sẽ không được phát hiện như vậy vì chúng nằm trong các cột không khớp.

Tuy nhiên, điều này dường như không phải là một vấn đề, ít nhất là trong các trường hợp thử nghiệm. Dường như một thử nghiệm giữa nhiều multisets như 1,2,32,3,4không bao giờ thực sự phải được thực hiện, bởi vì một số multiset trung gian đã cho kết quả âm tính và vì vậy chúng đã ở các phần khác nhau. Nếu điều này thực sự đúng, lý do không có nghi ngờ gì liên quan đến thực tế là các multisets được sắp xếp.

Tôi không có bằng chứng về điều này, mặc dù. Nó chỉ có vẻ để làm việc.

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ó rất ấn tượng.

Tôi đang cố gắng để hiểu nếu phương pháp bạn mô tả sẽ luôn hoạt động. Tôi thấy rằng trong n=k=4trường hợp chúng ta có một phần mới bắt đầu (0, 0, 3, 3), sự khác biệt liên tiếp được vectơ của phần đó và phần đa trước đó, (0, 0, 2, 3)chỉ có một điểm khác biệt, vậy "phần cho đến nay" làm cho phần này hoạt động như thế nào? (hoặc tương đương với kết quả bước trước đã được sử dụng thay vì (0, 0, 2, 3)?)
Jonathan Allan

Ah, tôi thấy bạn thực hiện một sự khác biệt liên tiếp. Có cái này nên luôn hoạt động! Bạn thực sự đang tìm kiếm các điểm tại đó có nhiều hơn một mục thay đổi, nhưng thay vì giao điểm nhiều bộ, giao lộ được đơn giản hóa - sẽ hoạt động kể từ khi các bộ biến đổi được sắp xếp để bắt đầu.
Jonathan Allan

@Jonathan ALLan Vâng, đó là sự khác biệt liên tiếp chứ không phải là giao lộ. Tôi vẫn không thấy rõ rằng nó sẽ luôn hoạt động, nhưng nếu bạn nói vậy ... :-)
Luis Mendo

1

PHP, 245 byte

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

Hãy thử trực tuyến!

Mở rộng

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

Đầu ra dưới dạng Chuỗi

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

n> 15 để chính xác hơn

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

Điều này dường như làm việc! Nhưng bạn có ý nghĩa gì bởi độ chính xác cao hơn?

@Lembik phiên bản ngắn cho lại 0cho (16**16-1)%16và phiên bản làm việc dài chỉ với độ chính xác những gì cần thiết cho n>15 bcmod(bcsub(bcpow(16,16),1),16)15 php.net/manual/en/ref.bc.php
Jörg Hülsermann
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.