โลภแบ่งรายการชุดค่าผสมด้วยการทำซ้ำอย่างโลภ


10

ก่อนคำจำกัดความไม่กี่:

  • รับnและkพิจารณารายการที่เรียงลำดับของMultisetsที่แต่ละชุดที่เราเลือก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

งาน

รหัสของคุณควรใช้เวลาสองมีปากเสียงและ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)

การชี้แจงว่าโลภหมายถึงอะไร: สำหรับแต่ละเซ็ตนั้นเราจะดูว่าสามารถเพิ่มเข้าไปในส่วนที่มีอยู่ได้หรือไม่ ถ้าเราสามารถเพิ่มมันได้ หากเราไม่สามารถเริ่มส่วนใหม่ได้ เราดูชุดย่อยตามลำดับที่เรียงไว้ในตัวอย่างที่ให้ไว้ด้านบน

เอาท์พุต

คุณสามารถแสดงผลการแบ่งพาร์ติชันในรูปแบบที่เหมาะสมตามที่คุณต้องการ อย่างไรก็ตามหลายชุดควรเขียนในแนวนอนในหนึ่งบรรทัด นั่นคือ Multiset แต่ละอันไม่ควรเขียนในแนวตั้งหรือกระจายข้ามหลายบรรทัด คุณสามารถเลือกวิธีแยกการแสดงชิ้นส่วนในเอาต์พุต

สมมติฐาน

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

สองบรรทัดว่างระหว่างส่วนต่าง ๆ

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;

คำอธิบาย:

ก่อนอื่นเราจะพบมัลติเซ็ตทั้งหมดที่มีกำลังดุร้าย:

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 == 0a == 1

หากทางแยกยาวไม่พอเราจะพิมพ์บรรทัดใหม่และล้างสแต็ก:

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

จากนั้นเราก็พิมพ์ multiset ปัจจุบัน:

disp(l(i,:));

ดูเหมือนว่าคุณจะแคร็กมัน! คุณอธิบายวิธีการของคุณได้ไหม

@Lembik ฉันได้เพิ่มคำอธิบาย
Steadybox

3

MATL , 34 ไบต์

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

ชิ้นส่วนจะถูกคั่นด้วยบรรทัดที่มีช่องว่าง

ลองออนไลน์!

คำอธิบาย

คำเตือน: ดูเหมือนว่าวิธีนี้จะใช้งานได้ (และในกรณีทดสอบ) แต่ฉันไม่ได้พิสูจน์ว่ามันทำเสมอ

Multisets ถูกจัดเรียงทั้งภายใน (เช่นแต่ละชุดมีรายการที่ไม่ลดลง) และภายนอก (เช่น Multiset Mมาก่อน Multiset Nถ้าMนำหน้าN lexicographically)

ในการคำนวณจุดตัดหลายชุดมัลติเซตที่เรียงลำดับจะถูกจัดเรียงเป็นแถวของเมทริกซ์และคำนวณความแตกต่างติดต่อกันตามแต่ละคอลัมน์ หากคอลัมน์ทั้งหมดยกเว้นอย่างน้อยหนึ่งคอลัมน์จะมีความแตกต่างทั้งหมดเท่ากับศูนย์ชุดย่อยจะอยู่ในส่วนเดียวกัน

การทดสอบนี้จะให้ผลลัพธ์เชิงลบที่ผิดพลาดสำหรับ Multisets เช่น(1,2,3)และ(2,3,4): แม้ว่า2 , 3มีรายการร่วมกันพวกเขาจะไม่ถูกตรวจพบว่าเป็นเช่นนั้นเพราะพวกเขาอยู่ในคอลัมน์ที่ไม่ตรงกัน

อย่างไรก็ตามนี่ไม่ได้เป็นปัญหา แต่อย่างน้อยในกรณีทดสอบ ดูเหมือนว่าการทดสอบระหว่าง Multisets เช่น1,2,3และ2,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

อ่าฉันเห็นว่าคุณทำสิ่งที่แตกต่างติดต่อกัน ใช่สิ่งนี้ควรใช้งานได้! คุณกำลังมองหาจุดที่มีการเปลี่ยนแปลงมากกว่าหนึ่งรายการ แต่แทนที่จะแยกหลายชุดเพียงแยกเวกเตอร์ - ซึ่งจะทำงานได้เนื่องจากชุด mutli ถูกเรียงลำดับเพื่อเริ่มต้นด้วย
Jonathan Allan

@JanathanAllan ใช่มันเป็นความแตกต่างติดต่อกันมากกว่าสี่แยก ฉันยังไม่เห็นชัดเจนว่ามันจะใช้งานได้เสมอ แต่ถ้าคุณพูดอย่างนั้น ... :-)
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
JörgHülsermann
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.