เมื่อกำหนดชุดของสแต็ค NXP โดยที่ N เป็นจำนวนสแต็คและ P เป็นความสามารถของสแต็คฉันจะคำนวณจำนวนสว็อปขั้นต่ำที่จำเป็นในการย้ายจากโหนดบางจุดในตำแหน่ง A ไปยังตำแหน่ง A ได้อย่างไร ฉันออกแบบเกมและเป้าหมายสุดท้ายคือเรียงลำดับสแต็คทั้งหมดเพื่อให้มีสีเดียวกัน
# Let "-" represent blank spaces, and assume the stacks are
stacks = [
['R', 'R', 'R', 'R'],
['Y', 'Y', 'Y', 'Y'],
['G', 'G', 'G', 'G'],
['-', '-', '-', 'B'],
['-', 'B', 'B', 'B']
]
ถ้าผมต้องการที่จะใส่ "B" ที่ดังกล่าวว่าstacks[1][1]
stacks[1] = ["-", "B", "Y", "Y"]
ฉันจะกำหนดจำนวนการเคลื่อนไหวขั้นต่ำที่ต้องทำได้อย่างไร
ฉันกำลังดูหลายวิธีฉันได้ลองใช้อัลกอริธึมทางพันธุกรรมที่สร้างการเคลื่อนไหวที่เป็นไปได้ทั้งหมดจากรัฐให้คะแนนพวกเขาและจากนั้นไปตามเส้นทางการให้คะแนนที่ดีที่สุดฉันยังพยายามเรียกใช้อัลกอริทึมของ Djikstra . ดูเหมือนง่ายอย่างน่าผิดหวัง แต่ฉันไม่สามารถหาวิธีที่จะให้มันทำงานในสิ่งอื่นนอกจากเวลาเอ็กซ์โพเนนเชียล มีอัลกอริทึมที่ฉันขาดซึ่งสามารถใช้ได้ที่นี่หรือไม่?
แก้ไข
ฉันได้เขียนฟังก์ชันนี้เพื่อคำนวณจำนวนการเคลื่อนไหวขั้นต่ำที่ต้องการ: สแต็ค: รายชื่อตัวละครที่แสดงถึงส่วนต่าง ๆ ในสแต็ค [0] [0] เป็นสแต็กด้านบน [0] stack_ind: ดัชนีของ สแต็คที่ชิ้นส่วนจะถูกเพิ่มลงในความต้องการ _ ชิ้น: ชิ้นส่วนที่ควรเพิ่มลงในสแต็ค needs_index: ดัชนีที่ควรตั้งชิ้นส่วน
def calculate_min_moves(stacks, stack_ind, needs_piece, needs_index):
# Minimum moves needed to empty the stack that will receive the piece so that it can hold the piece
num_removals = 0
for s in stacks[stack_ind][:needs_index+1]:
if item != "-":
num_removals += 1
min_to_unlock = 1000
unlock_from = -1
for i, stack in enumerate(stacks):
if i != stack_ind:
for k, piece in enumerate(stack):
if piece == needs_piece:
if k < min_to_unlock:
min_to_unlock = k
unlock_from = i
num_free_spaces = 0
free_space_map = {}
for i, stack in enumerate(stacks):
if i != stack_ind and i != unlock_from:
c = stack.count("-")
num_free_spaces += c
free_space_map[i] = c
if num_removals + min_to_unlock <= num_free_spaces:
print("No shuffling needed, there's enough free space to move all the extra nodes out of the way")
else:
# HERE
print("case 2, things need shuffled")
แก้ไข: กรณีทดสอบในกอง:
stacks = [
['R', 'R', 'R', 'R'],
['Y', 'Y', 'Y', 'Y'],
['G', 'G', 'G', 'G'],
['-', '-', '-', 'B'],
['-', 'B', 'B', 'B']
]
Case 1: stacks[4][1] should be 'G'
Move 'B' from stacks[4][1] to stacks[3][2]
Move 'G' from stacks[2][0] to stacks[4][1]
num_removals = 0 # 'G' is directly accessible as the top of stack 2
min_to_unlock = 1 # stack 4 has 1 piece that needs removed
free_spaces = 3 # stack 3 has free spaces and no pieces need moved to or from it
moves = [[4, 3], [2, 4]]
min_moves = 2
# This is easy to calculate
Case 2: stacks[0][3] should be 'B'
Move 'B' from stacks[3][3] to stack[4][0]
Move 'R' from stacks[0][0] to stacks[3][3]
Move 'R' from stacks[0][1] to stacks[3][2]
Move 'R' from stacks[0][2] to stacks[3][1]
Move 'R' from stacks[0][3] to stacks[3][0]
Move 'B' from stacks[4][0] to stacks[0][3]
num_removals = 0 # 'B' is directly accessible
min_to_unlock = 4 # stack 0 has 4 pieces that need removed
free_spaces = 3 # If stack 3 and 4 were switched this would be 1
moves = [[3, 4], [0, 3], [0, 3], [0, 3], [0, 3], [4, 0]]
min_moves = 6
#This is hard to calculate
การติดตั้งโค้ดที่แท้จริงไม่ใช่ส่วนที่ยาก แต่มันคือการกำหนดวิธีการใช้อัลกอริธึมที่แก้ปัญหาที่ฉันกำลังดิ้นรนอยู่
ตามคำขอของ @ YonIif ฉันได้สร้างส่วนสำคัญสำหรับปัญหา
เมื่อมันทำงานมันจะสร้างอาเรย์แบบสุ่มของสแต็คและเลือกชิ้นส่วนแบบสุ่มที่ต้องแทรกลงในสแต็กแบบสุ่มที่ตำแหน่งสุ่ม
การรันมันจะพิมพ์สิ่งที่เป็นรูปแบบนี้ไปยังคอนโซล
All Stacks: [['-', '-', 'O', 'Y'], ['-', 'P', 'P', 'O'], ['-', 'P', 'O', 'Y'], ['Y', 'Y', 'O', 'P']]
Stack 0 is currently ['-', '-', 'O', 'Y']
Stack 0 should be ['-', '-', '-', 'P']
อัพเดทสถานะ
ฉันมุ่งมั่นมากที่จะแก้ปัญหานี้อย่างใด
โปรดทราบว่ามีวิธีที่จะลดจำนวนกรณีเช่นกรณีที่ @Hans Olsson พูดถึงในความคิดเห็น แนวทางล่าสุดของฉันเกี่ยวกับปัญหานี้คือการพัฒนาชุดของกฎที่คล้ายกับที่กล่าวถึงและใช้มันในอัลกอริทึม generational
กฎเช่น:
อย่าย้อนกลับการเคลื่อนไหว ไปจาก 1-> 0 แล้ว 0-> 1 (ไม่เข้าท่า)
อย่าขยับหมากสองครั้งติดต่อกัน อย่าย้ายจาก 0 -> 1 จากนั้น 1 -> 3
ให้ย้ายจากสแต็ก [X] ไปยังสแต็ค [Y] แล้วย้ายเป็นจำนวนมากจากนั้นย้ายจากสแต็ก [Y] ไปยังสแต็ก [Z] หากสแต็ก [Z] อยู่ในสถานะเดียวกับตอนที่ย้าย จากสแต็ค [X] ไปเป็นสแต็ค [Y] การเคลื่อนไหวอาจถูกกำจัดได้โดยการย้ายจากสแต็ก [X] ไปยังสแต็ค [Z] โดยตรง
ขณะนี้ฉันกำลังเข้าใกล้ปัญหานี้ด้วยความพยายามในการสร้างกฎที่เพียงพอซึ่งจะลดจำนวนการเคลื่อนไหว "ที่ถูกต้อง" ให้เหลือน้อยที่สุดเพื่อให้สามารถคำนวณคำตอบได้โดยใช้อัลกอริทึม generational หากใครสามารถนึกถึงกฎเพิ่มเติมฉันจะสนใจฟังความคิดเห็นเหล่านั้น
ปรับปรุง
ขอบคุณคำตอบของ @RootTwo ฉันมีความก้าวหน้าเล็กน้อยซึ่งฉันจะสรุปไว้ที่นี่
ไปสู่ความก้าวหน้า
กำหนดความสูงของเป้าหมายเป็นความลึกที่ชิ้นส่วนเป้าหมายจะต้องอยู่ในสแต็กปลายทาง
เมื่อใดก็ตามที่ชิ้นส่วนเป้าหมายถูกวางไว้ที่ดัชนี <= stack_height - ความสูงของเป้าหมายจะมีเส้นทางที่สั้นที่สุดสู่ชัยชนะผ่านวิธี clear_path ()
Let S represent some solid Piece.
IE
Stacks = [ [R, R, G], [G, G, R], [-, -, -] ]
Goal = Stacks[0][2] = R
Goal Height = 2.
Stack Height - Goal Height = 0
เมื่อได้รับสแต็กบางอย่างstack[0] = R
เกมจะชนะ
GOAL
[ [ (S | -), (S | -), (S | -) ], [R, S, S], [(S | - ), (S | -), (S | -)] ]
เนื่องจากเป็นที่ทราบกันว่ามีช่องว่างว่างอย่างน้อย stack_height อยู่เสมอดังนั้นกรณีที่เป็นไปได้ที่เลวร้ายที่สุดคือ:
[ [ S, S, !Goal ], [R, S, S], [-, -, -]
เนื่องจากเรารู้ว่าชิ้นส่วนเป้าหมายไม่สามารถอยู่ในเป้าหมายหรือเป็นเกมที่ชนะ ในกรณีนี้จำนวนขั้นต่ำของการเคลื่อนไหวที่ต้องการคือการเคลื่อนไหว:
(0, 2), (0, 2), (0, 2), (1, 0)
Stacks = [ [R, G, G], [-, R, R], [-, -, G] ]
Goal = Stack[0][1] = R
Stack Height - Goal Height = 1
เมื่อได้รับสแต็กบางอย่างstack[1] = R
เกมจะชนะ
GOAL
[ [ (S | -), (S | -), S], [ (S | -), R, S], [(S | -), (S | -), (S | -)]
เรารู้ว่ามีช่องว่างว่างไว้อย่างน้อย 3 ช่องดังนั้นกรณีที่เป็นไปได้ที่สุด:
[ [ S, !Goal, S], [S, R, S], [ -, -, - ]
ในกรณีนี้จำนวนการเคลื่อนไหวขั้นต่ำจะเป็นการเคลื่อนไหว:
(1, 2), (0, 2), (0, 2), (1, 0)
สิ่งนี้จะระงับทุกกรณี
ดังนั้นปัญหาได้ถูกลดลงเป็นปัญหาในการค้นหาจำนวนการเคลื่อนไหวขั้นต่ำที่จำเป็นในการวางชิ้นส่วนเป้าหมายที่หรือสูงกว่าที่ความสูงของเป้าหมาย
สิ่งนี้จะแยกปัญหาออกเป็นชุดย่อยของปัญหา:
เมื่อสแต็คปลายทางมีชิ้นส่วนที่สามารถเข้าถึงได้! = ชิ้นส่วนเป้าหมายให้พิจารณาว่ามีตำแหน่งที่ถูกต้องสำหรับชิ้นส่วนนั้นหรือถ้าชิ้นส่วนควรอยู่ที่นั่นในขณะที่ชิ้นส่วนอื่นถูกสลับ
เมื่อสแต็คปลายทางมีชิ้นส่วนที่สามารถเข้าถึงได้ == ชิ้นส่วนเป้าหมายให้พิจารณาว่าสามารถลบออกและวางไว้ที่ความสูงเป้าหมายที่ต้องการหรือถ้าชิ้นส่วนควรอยู่ในขณะที่อีกสแนป
เมื่อทั้งสองกรณีข้างต้นต้องการสลับชิ้นส่วนอื่นให้พิจารณาว่าชิ้นส่วนใดที่จะสลับเพื่อเพิ่มขึ้นเพื่อให้ชิ้นส่วนเป้าหมายบรรลุความสูงของเป้าหมาย
สแต็คปลายทางควรมีการประเมินเคสก่อนเสมอ
IE
stacks = [ [-, R, G], [-, R, G], [-, R, G] ]
Goal = stacks[0][1] = G
การตรวจสอบ Stack Stack ก่อนจะทำให้:
(0, 1), (0, 2), (1, 0), (2, 0) = 4 Moves
ไม่สนใจกลุ่มเป้าหมาย:
(1, 0), (1, 2), (0, 1), (0, 1), (2, 0) = 5 Moves