การแลกเปลี่ยนสแต็ก


23

ปัญหา

สมมติว่าคุณมีสแต็ค N ชื่อ S 1ถึง S Nโดยที่ S k (k = 1 ถึง N) แต่ละอันมี N สำเนาของหมายเลข k

ตัวอย่างเช่นเมื่อ N = 3 กองที่มีลักษณะเช่นนี้:

1  2  3  <- top of stack
1  2  3
1  2  3  <- bottom of stack
=======
1  2  3  <- stack index

ที่นี่มีการจัดทำดัชนี 3 กองเป็น 1, 2 และ 3 และแต่ละอันมี N อินสแตนซ์ของดัชนีของตนเอง

เป้าหมายคือการจัดเรียงสแต็คใหม่ให้แต่ละกลุ่มมีหมายเลข 1 ถึง N ตามลำดับจากบนลงล่าง

เช่นสำหรับ N = 3 เป้าหมายคือจัดเรียงสแต็คใหม่เป็น:

1  1  1
2  2  2
3  3  3
=======
1  2  3

การกระทำที่เดียวที่คุณสามารถดำเนินการกับสแต็คจะสละตัวเลขด้านบนจากหนึ่งในกอง (popping) แล้วทันทีที่วางไว้ที่ด้านบนของสแต็คที่แตกต่างกัน (การผลักดัน) ภายใต้ข้อกำหนดเหล่านี้:

  • จำนวนสามารถถูกส่งไปยังสแต็กได้ถ้ามันน้อยกว่าหรือเท่ากับจำนวนสูงสุดของสแต็กนั้น

    • เช่น1สามารถผลักลงบนสแต็กด้วย a 1, 2หรือ3ที่ด้านบน แต่2สามารถผลักลงบนสแต็กที่มี2หรือ3(หรือสูงกว่า) ที่ด้านบนเท่านั้น

    • สิ่งนี้มีเอฟเฟกต์ที่สแต็คเพิ่มขึ้นเป็นจำเจเสมอจากบนลงล่าง

  • สแต็กที่ไม่มีข้อยกเว้นใด ๆ อาจถูกดึงออกมาและถ้าเป็นไปได้ว่ากระสุนที่ผ่านมานั้นเป็นที่พอใจ

  • สามารถกดหมายเลขใดก็ได้ลงในสแต็กเปล่า

  • กองซ้อนไม่มีขีดจำกัดความสูงสูงสุด

  • สแต็คไม่สามารถสร้างหรือทำลายได้มี N ตัวเสมอ

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

(การฝึกฝนไพ่สำรับเป็นวิธีที่ดีในการทำความเข้าใจกับปัญหา)

ท้าทาย

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

1  2  3  4  5
1  2  3  4  5
1  2  3  4  5
1  2  3  4  5
1  2  3  4  5
=============
1  2  3  4  5

(N = 5 กรณี)

ไปยังสถานะสุดท้าย:

1  1  1  1  1
2  2  2  2  2
3  3  3  3  3
4  4  4  4  4
5  5  5  5  5
=============
1  2  3  4  5

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

ตัวอย่างเช่นนี่คือผลลัพธ์ที่ใช้ได้สำหรับกรณี N = 3:

1 2  [move the top number on stack 1 to the top of stack 2]
1 2  [repeat]
1 2  [repeat]
3 1  [move the top number on stack 3 to the top of stack 1]
2 3  [etc.]
2 3
2 3
2 1
2 1
2 1
3 1
3 1
3 1
3 2
1 2
1 2
1 2
1 3
2 3
2 3
2 3
1 2
3 2
3 1

หมายเหตุ

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

    • ดังนั้นจะไม่เป็นไรถ้าพูดว่ามีการเคลื่อนไหวบางอย่างซ้ำ ๆ และกลับด้านทันที
    • การแทงและผลักไปที่กองซ้อนเดียวกันในการเคลื่อนที่ครั้งเดียว2 2ก็ทำได้เช่นกัน (แม้ว่าจะไม่มีจุดหมายแน่นอน)
  • ผลลัพธ์ของคุณจะต้องกำหนดและ จำกัด

  • โปรดจำไว้ว่าสแต็คมีการจัดทำดัชนีแบบ 1 ไม่อนุญาตการสร้างดัชนีแบบ 0

  • แน่นอนว่ามากกว่า 9 ควรทำงานเช่นเดียวกับหลักเดียว N

  • หากต้องการคุณสามารถใช้อักขระ ASCIIสองตัวที่แตกต่างกันและไม่ใช่ตัวเลขที่พิมพ์ได้แทนช่องว่างและบรรทัดใหม่ ขึ้นบรรทัดใหม่ (หรือการขึ้นบรรทัดใหม่แทน) ในผลลัพธ์นั้นใช้ได้

เกณฑ์การให้คะแนน

รหัสที่สั้นที่สุดในหน่วยไบต์ชนะ Tiebreaker เป็นคำตอบที่โหวตให้สูงกว่า

คะแนนบราวนี่บราวนี่ถ้าคุณสามารถแสดงอัลกอริทึมของคุณได้ดีที่สุด


หยุดด้วย "จุดพิเศษสำหรับสิ่งเล็ก ๆ " ไร้สาระ> _>
user48538

18
@ zyabin101 คุณเพิ่งเสียโอกาสกับบราวนี่
งานอดิเรกของ Calvin

9
คุณสร้างชื่อที่ยอดเยี่ยมเช่นนี้เสมอ!
Luis Mendo

@HelkaHomba-._(._.)_.-
user48538

ผลลัพธ์ที่เป็นไปได้ที่คุณมีสำหรับกรณีที่N=3เหมาะสมที่สุดหรือไม่
R. Kap

คำตอบ:


9

Pyth 96 94 ไบต์

Mt*Q+++bGdHM|%+y_GHQQg1 2++Qd1g2 3g2 1g3 1++Qd2Vr3QgNtN++QdN;g1QVStQVStQI<NHgnNHnNtH)++nN0dnNH

ลองที่นี่

มันทำงานยังไง?

คำอธิบายนี้จะใช้ N = 5

ส่วนที่ 1: สร้างเลเยอร์ด้านล่างของทุก ๆ สแต็ค

เหตุผลที่ต้องใช้รหัสแยกต่างหากก็เพราะว่าทุกสแต็กจำเป็นต้องใช้: 4 รายการแรกจะต้องใส่ 5 ข้างใต้พวกเขาและสแต็กสุดท้ายต้องจัดให้มี 5s ซึ่งหมายความว่าเราไม่สามารถย้าย 4s ทั้งหมดที่ไหนสักแห่งใส่ 5 ตรงนั้นแล้วย้าย 4s กลับ

การสร้างภาพ: (วงเล็บหมายถึงสิ่งที่จะถูกย้าย)

     _
11111 |
22222 |_ Can't move 4s here, not monotonically increasing
33333_|
(44444)------------??? Where to put the 4s?
55555 <- Must supply the 5 that will be moved

ในการแลกเปลี่ยนครั้งแรกเราจะย้าย 1s ทั้งหมดไปที่สแต็กที่สองย้าย 5 ไปที่สแต็กแรก (ซึ่งว่างเปล่าตอนนี้) ย้าย 1s ไปที่สแต็กที่สามย้าย 2s ไปที่แรก สแต็กย้าย 1s กลับไปที่สแต็กแรกและสุดท้ายย้าย 5 ไปยังสแต็กที่สอง

(11111)-----.
2222211111<-'
===============================
5<---------.
2222211111 : (from stack 5)
===============================
5
22222(11111)-.
3333311111<--'
===============================
522222<-.
(22222)-'
3333311111
===============================
52222211111<-.
             |
33333(11111)-'
===============================
52222211111
5<-----.
33333  |
44444  |
555(5)-'

ตอนนี้เรามีพื้นที่ว่างที่จะย้ายสแต็คเข้ามา (สแต็ค 2 ซึ่งมีเพียง 5 ที่อยู่ในตำแหน่งที่ถูกต้อง) เราสามารถย้าย 3s ทั้งหมดไปยังสแต็ก 2 และวาง 5 ในสแต็ค 3 จากนั้นเราสามารถทำซ้ำ สิ่งเดียวกันสำหรับ stack 4 และตอนนี้เราได้รับ 5s ทั้งหมดในตำแหน่งที่ถูกต้อง! และอีกสิ่งหนึ่ง: เราจะย้าย 1s ทั้งหมดไปยังกอง 5 เพื่อให้เราได้รับการตั้งค่าที่ดีสำหรับการแลกเปลี่ยนกองซ้อนครั้งต่อไป

522222(11111)-.
533333        |
544444        |
5             |
511111<-------'

ตอนที่ 2: ทำทุกอย่างอื่น :)

ตอนนี้ง่ายกว่ามากเพราะตอนนี้เราจะมีสแต็กฟรีเพื่อย้ายหมายเลขอื่น ๆ ที่เราต้องใช้ในการเล่น ก่อนอื่นเราหาว่า 4 อยู่ที่ไหน การตรวจสอบเล็กน้อยจะแสดงให้เห็นว่ามันจะเป็น 1 เสมอจากจุดเริ่มต้นหรือ 2 ข้างบนสแต็กสุดท้าย ทีนี้เราก็ลงไปเรื่อย ๆ วางกอง 4 ลงในสแต็กถ้ามันว่างหรือย้ายตัวเลขอื่น ๆ ขึ้นมา 1 กอง ตอนนี้เรามี 4s ทั้งหมดแล้ว

522222<------.
533333<----. |
544444-.-.-'-'
5<-----' |
511111<--'
===============================
5433333
54
54
5411111
5422222

ตอนนี้เรารู้แล้วว่า 3s นั้นเป็น 2 สแต็คด้านบนตรงที่ 4s อยู่ที่ไหน ซึ่งหมายความว่าเราสามารถทำสิ่งเดียวกันกับที่เราทำกับ 4s! และเมื่อปรากฎว่าเราสามารถทำสิ่งนี้ได้ตราบใดที่เราห่อดัชนีสแต็กไปทางด้านอื่น ๆ

5433333-'wrap around 543
54                   543
54                   54311111
5411111 .----------->54322222
5422222 |2 stacks up 543

และดังนั้นเราสามารถทำเช่นนี้ต่อไปจนกว่าเราจะได้แลกเปลี่ยนกองทั้งหมด

คำอธิบายรหัส:

ก่อนอื่น: ตัวแปรที่กำหนดไว้ล่วงหน้า (สำคัญ)

Q: Evaluated input.
b: The newline character, '\n'
d: A space, ' '

มีคำจำกัดความแลมบ์ดา 2 คำ

M           | g(G)(H), used for moving Q numbers at a time.
            | We will call these Q numbers a "(number) block"
 t          | Tail, used to remove beginning newline
  *Q        | Repeat the following Q times
    +++bGdH | '\n' + G + ' ' + H. Just a whole bunch of concatenating.
            |
M           | n(G)(H), used for figuring out which stacks to move from
 |       Q  | If the following code is 0 (false), then use Q instead
  %     Q   | Mod Q
   +   H    | Add H
    y       | Multiply by 2
     _G     | Negate (remember in the explanation part 2? Always 2 stacks above?)

การแลกเปลี่ยนสแต็ค: ตอนที่ 1

g1 2                       | Move the 1 block to stack 2
    ++Qd1                  | Move a Q to stack 1
         g2 3              | Move the 1 block to stack 3
             g2 1          | Move the 2 block to stack 1
                 g3 1      | Move the 1 block back to stack 1
                     ++Qd2 | Move a Q to stack 2
 v---Code-continuation---' |I don't have enough room!!!
Vr3Q                       | For N in range(3, Q)
    gNtN                   | Move the number block in stack N up 1
        ++QdN              | Move a Q to stack N
             ;g1Q          | End for loop; move the 1 block to the last stack

การแลกเปลี่ยนสแต็ค: ตอนที่ 2

VStQ                           | For N in [1, 2, ..., Q - 1]
    VStQ                       | For H in [1, 2, ..., Q - 1]
        I<NH                   | If N < H
            g                  | Number block move
             nNH               |  (find number block)
                nNtH           |  (find the previous stack)
                    )          | End "For H"
                     ++nN0dnNH | Find start, move number to next location down

ฉันรู้อยู่แล้วว่าฉันไม่ได้รับคะแนนบราวนี่เพราะฉันสามารถดูวิธีที่มีประสิทธิภาพและซับซ้อนมากขึ้น :(

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.