วิธีค้นหาจำนวนการเคลื่อนไหวขั้นต่ำเพื่อย้ายรายการไปยังตำแหน่งในกองซ้อน?


12

สแต็ค

เมื่อกำหนดชุดของสแต็ค 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)

สิ่งนี้จะระงับทุกกรณี

ดังนั้นปัญหาได้ถูกลดลงเป็นปัญหาในการค้นหาจำนวนการเคลื่อนไหวขั้นต่ำที่จำเป็นในการวางชิ้นส่วนเป้าหมายที่หรือสูงกว่าที่ความสูงของเป้าหมาย

สิ่งนี้จะแยกปัญหาออกเป็นชุดย่อยของปัญหา:

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

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

  3. เมื่อทั้งสองกรณีข้างต้นต้องการสลับชิ้นส่วนอื่นให้พิจารณาว่าชิ้นส่วนใดที่จะสลับเพื่อเพิ่มขึ้นเพื่อให้ชิ้นส่วนเป้าหมายบรรลุความสูงของเป้าหมาย

สแต็คปลายทางควรมีการประเมินเคสก่อนเสมอ

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

2
คุณลองA *หรือยัง มันค่อนข้างคล้ายกับอัลกอริทึมของ Dijkstra แต่บางครั้งมันก็เร็วกว่ามาก
Yonlif

1
คุณช่วยแบ่งปันลิงค์ repo GitHub ได้ไหม? ฉันต้องการทดลองตัวเองถ้าไม่เป็นไร @Tristen
Yonlif

1
หลังจากดูครั้งแรกปัญหานี้ดูเหมือนว่าจะยาก มันอาจจะไม่ได้อยู่ใน NP (ยังไม่เสร็จสมบูรณ์) เพราะแม้ว่าฉันจะให้ทางออกที่ดีที่สุดแก่คุณคุณก็ไม่สามารถตรวจสอบได้อย่างง่ายดาย สิ่งนี้เป็นที่รู้จักสำหรับปัญหาการปรับให้เหมาะสมกับการเรียงสับเปลี่ยน ผมขอแนะนำให้ไปที่โพสต์ข้ามปัญหาที่CS ดูอัลกอริทึมการประมาณค่าสำหรับปัญหานี้ นี่เป็นปัญหาที่ค่อนข้างยาก แต่ควรมีการประมาณที่เหมาะสม คล้ายกัน: หอคอยโดยพลการแห่งฮานอย
DarioHett

1
@DarioHett นั่นคือสิ่งที่ฉันเป็นห่วง! ฉันมีนิ้วของฉันข้ามว่ามันจะไม่จบลงด้วยการเป็นปัญหา NP-Hard แต่ฉันก็มีความรู้สึกว่ามันอาจจะเป็นหนึ่ง ฉันโชคดีขึ้นด้วยอัลกอริธึมทางพันธุกรรมและยังมีฟังก์ชั่นการให้คะแนนพิเศษที่ให้คะแนนการเคลื่อนไหว ฉันจะดูหอคอย Arbitrary ของฮานอย! ขอบคุณสำหรับคำแนะนำ
Tristen

1
หากคุณพยายามที่จะสร้างตัวต่อแบบสุ่ม - อย่าลืมเคลื่อนย้ายสิ่งที่ซ้ำซ้อนอย่างเห็นได้ชัด (เคลื่อนย้ายบางสิ่งบางอย่างกลับหลังการเคลื่อนที่ไปข้างหน้าหรือเคลื่อนที่สองขั้นตอนเมื่อมีใครพอแล้วและร่วมกับการเคลื่อนไหวที่ไม่เกี่ยวข้อง
Hans Olsson

คำตอบ:


1

ฉันมาพร้อมกับสองตัวเลือก แต่ไม่มีใครสามารถแก้ปัญหากรณีที่ 2 ได้ในเวลาที่เหมาะสม ตัวเลือกแรกใช้ A * โดยมีการวัดระยะห่างของสตริงเป็น h (n) ตัวเลือกที่สองคือ IDA * ฉันทดสอบการวัดความคล้ายคลึงกันของสตริงจำนวนมากฉันใช้ smith-waterman ในแนวทางของฉัน ฉันเปลี่ยนสัญกรณ์ของคุณเพื่อแก้ไขปัญหาได้เร็วขึ้น ฉันได้เพิ่มตัวเลขที่ส่วนท้ายของแต่ละหลักเพื่อตรวจสอบว่าชิ้นส่วนถูกย้ายสองครั้งหรือไม่

นี่คือกรณีที่ฉันได้ทดสอบ:

start = [
 ['R1', 'R2', 'R3', 'R4'], 
 ['Y1', 'Y2', 'Y3', 'Y4'], 
 ['G1', 'G2', 'G3', 'G4'], 
 ['B1'], 
 ['B2', 'B3', 'B4']
]

case_easy = [
 ['R', 'R', 'R', 'R'], 
 ['Y', 'Y', 'Y', 'Y'], 
 ['G', 'G', 'G'], 
 ['B', 'B'], 
 ['B', 'B', 'G']
]


case_medium = [
 ['R', 'R', 'R', 'R'], 
 ['Y', 'Y', 'Y', 'B'], 
 ['G', 'G', 'G'], 
 ['B'],
 ['B', 'B', 'G', 'Y']
]

case_medium2 = [
 ['R', 'R', 'R' ], 
 ['Y', 'Y', 'Y', 'B'], 
 ['G', 'G' ], 
 ['B', 'R', 'G'],
 ['B', 'B', 'G', 'Y']
]

case_hard = [
 ['B'], 
 ['Y', 'Y', 'Y', 'Y'], 
 ['G', 'G', 'G', 'G'], 
 ['R','R','R', 'R'], 
 ['B','B', 'B']
]

นี่คือรหัส A *:

from copy import deepcopy
from heapq import *
import time, sys
import textdistance
import os

def a_star(b, goal, h):
    print("A*")
    start_time = time.time()
    heap = [(-1, b)]
    bib = {}
    bib[b.stringify()] = b

    while len(heap) > 0:
        node = heappop(heap)[1]
        if node == goal:
            print("Number of explored states: {}".format(len(bib)))
            elapsed_time = time.time() - start_time
            print("Execution time {}".format(elapsed_time))
            return rebuild_path(node)

        valid_moves = node.get_valid_moves()
        children = node.get_children(valid_moves)
        for m in children:
          key = m.stringify()
          if key not in bib.keys():
            h_n = h(key, goal.stringify())
            heappush(heap, (m.g + h_n, m)) 
            bib[key] = m

    elapsed_time = time.time() - start_time
    print("Execution time {}".format(elapsed_time))
    print('No Solution')

นี่คือรหัส IDA *:

#shows the moves done to solve the puzzle
def rebuild_path(state):
    path = []
    while state.parent != None:
        path.insert(0, state)
        state = state.parent
    path.insert(0, state)
    print("Number of steps to solve: {}".format(len(path) - 1))
    print('Solution')

def ida_star(root, goal, h):
    print("IDA*")
    start_time = time.time()
    bound = h(root.stringify(), goal.stringify())
    path = [root]
    solved = False
    while not solved:
        t = search(path, 0, bound, goal, h)
        if type(t) == Board:
            solved = True
            elapsed_time = time.time() - start_time
            print("Execution time {}".format(elapsed_time))
            rebuild_path(t)
            return t
        bound = t

def search(path, g, bound, goal, h):

    node = path[-1]
    time.sleep(0.005)
    f = g + h(node.stringify(), goal.stringify())

    if f > bound: return f
    if node == goal:
        return node

    min_cost = float('inf')
    heap = []
    valid_moves = node.get_valid_moves()
    children = node.get_children(valid_moves)
    for m in children:
      if m not in path:
        heappush(heap, (m.g + h(m.stringify(), goal.stringify()), m)) 

    while len(heap) > 0:
        path.append(heappop(heap)[1])
        t = search(path, g + 1, bound, goal, h)
        if type(t) == Board: return t
        elif t < min_cost: min_cost = t
        path.pop()
    return min_cost

class Board:
  def __init__(self, board, parent=None, g=0, last_moved_piece=''):
    self.board = board
    self.capacity = len(board[0])
    self.g = g
    self.parent = parent
    self.piece = last_moved_piece

  def __lt__(self, b):
    return self.g < b.g

  def __call__(self):
    return self.stringify()

  def __eq__(self, b):
    if self is None or b is None: return False
    return self.stringify() == b.stringify()

  def __repr__(self):
    return '\n'.join([' '.join([j[0] for j in i]) for i in self.board])+'\n\n'

  def stringify(self):
    b=''
    for i in self.board:
      a = ''.join([j[0] for j in i])
      b += a + '-' * (self.capacity-len(a))

    return b

  def get_valid_moves(self):
    pos = []
    for i in range(len(self.board)):
      if len(self.board[i]) < self.capacity:
        pos.append(i)
    return pos

  def get_children(self, moves):
    children = []
    for i in range(len(self.board)):
      for j in moves:
        if i != j and self.board[i][-1] != self.piece:
          a = deepcopy(self.board)
          piece = a[i].pop()
          a[j].append(piece)
          children.append(Board(a, self, self.g+1, piece))
    return children

การใช้งาน:

initial = Board(start)
final1 = Board(case_easy)
final2 = Board(case_medium)
final2a = Board(case_medium2)
final3 = Board(case_hard)

x = textdistance.gotoh.distance

a_star(initial, final1, x)
a_star(initial, final2, x)
a_star(initial, final2a, x)

ida_star(initial, final1, x)
ida_star(initial, final2, x)
ida_star(initial, final2a, x)

0

ในความคิดเห็นที่คุณพูดมี N กองที่มีความจุ P และมีพื้นที่ว่าง P เสมอ หากเป็นกรณีนี้ดูเหมือนว่าอัลกอริทึมนี้จะทำงานในelseส่วนของรหัสของคุณ (เช่นเมื่อnum_removals + min_to_unlock > num_free_spaces):

  1. ค้นหาชิ้นส่วนที่ต้องการซึ่งอยู่ใกล้กับด้านบนสุดของสแต็ก
  2. ย้ายชิ้นส่วนทั้งหมดจากด้านบนชิ้นส่วนที่ต้องการในลักษณะที่มีหนึ่งกอง (ไม่ใช่กองปลายทาง) ที่มีพื้นที่ว่างด้านบน หากจำเป็นให้ย้ายชิ้นส่วนจากสแต็กปลายทางหรือสแต็กอื่น หากพื้นที่เปิดโล่งเพียงด้านบนของสแต็กปลายทางให้ย้ายชิ้นส่วนที่นั่นเพื่อเปิดด้านบนของสแต็กอื่น เรื่องนี้เป็นไปได้เสมอเพราะมีช่องว่าง P และส่วนใหญ่ P-1 ที่จะย้ายจากด้านบนของชิ้นที่ต้องการ
  3. ย้ายชิ้นส่วนที่ต้องการไปยังตำแหน่งที่ว่างด้านบนของสแต็ก
  4. ย้ายชิ้นส่วนจากสแต็คปลายทางจนกว่าปลายทางจะเปิด
  5. ย้ายชิ้นส่วนที่ต้องการไปยังปลายทาง

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

0

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

p คืออะไร? สำหรับทุกคอลัมน์จะกำหนด p เป็นจำนวนบล็อกที่ยังต้องลบออกก่อนที่สีทั้งหมดในคอลัมน์นั้นจะเป็นสีที่ต้องการ สมมติว่าเราต้องการให้บล็อกสีแดงสิ้นสุดลงในคอลัมน์ซ้ายสุด (ฉันจะกลับไปที่บล็อกในภายหลัง) และสมมติว่ามีบล็อกสีแดงหนึ่งบล็อกที่ด้านล่างจากนั้นมีสีเหลืองอยู่ด้านบนของบล็อกนั้นอีกหนึ่งบล็อกที่ด้านบนของ นั่นและจากนั้นเป็นพื้นที่ว่าง จากนั้น p = 2 สำหรับคอลัมน์นี้ (สองช่วงตึกที่จะลบก่อนที่ทั้งหมดจะเป็นสีแดง) คำนวณ p สำหรับคอลัมน์ทั้งหมด สำหรับคอลัมน์ที่ควรจะว่างเปล่า p เท่ากับจำนวนบล็อกที่อยู่ในนั้น (ทั้งหมดควรไป) P สำหรับสถานะปัจจุบันคือผลรวมของ p ทั้งหมดสำหรับคอลัมน์ทั้งหมด

เมื่อ p = 0 คอลัมน์ทั้งหมดมีสีเดียวกันและหนึ่งคอลัมน์ว่างเปล่าเกมจึงสิ้นสุด

ด้วยการเลือกการเคลื่อนไหวที่ลด p (หรืออย่างน้อยก็ไม่เพิ่ม p) เรากำลังเคลื่อนที่ไปในทิศทางที่ถูกต้องนี่คือความคิดของฉันถึงความแตกต่างที่สำคัญกับอัลกอริธึมเส้นทางที่สั้นที่สุด: Dijkstra ไม่มีความคิดว่าเขาเคลื่อนที่ไปในทิศทางที่ถูกต้องหรือไม่ จุดสุดยอดเขากำลังสืบสวนอยู่

แล้วเราจะกำหนดได้อย่างไรว่าแต่ละสีควรจะจบลงอย่างไร โดยทั่วไปโดยการกำหนด p สำหรับทุกโอกาส เช่นเริ่มต้นด้วยสีแดง / สีเหลือง / สีเขียว / ว่างเปล่าคำนวณ p จากนั้นไปที่สีแดง / สีเหลือง / สีที่ว่างเปล่า / สีเขียวคำนวณ p และอื่น ๆ ใช้ตำแหน่งเริ่มต้นด้วย p ต่ำสุด สิ่งนี้ใช้เวลา n! การคำนวณ สำหรับ n = 8 นี่คือ 40320 ซึ่งสามารถทำได้ ข่าวร้ายก็คือคุณจะต้องตรวจสอบตำแหน่งเริ่มต้นทั้งหมดด้วยค่า p ต่ำสุดที่เท่ากัน ข่าวดีก็คือคุณสามารถลืมส่วนที่เหลือ

มีความไม่แน่นอนทางคณิตศาสตร์อยู่สองประการที่นี่ ที่หนึ่ง: เป็นไปได้ไหมที่มีเส้นทางที่สั้นกว่าซึ่งใช้ท่าที่ไม่ดี? ดูเหมือนว่าเป็นไปไม่ได้ฉันไม่พบตัวอย่างตัวอย่าง แต่ฉันไม่พบข้อพิสูจน์ สอง: เป็นไปได้ไหมที่เมื่อเริ่มต้นด้วยตำแหน่งเริ่มต้นที่ไม่เหมาะสม (เช่นไม่ใช่ตำแหน่งต่ำสุด) จะมีเส้นทางที่สั้นกว่ากว่าตำแหน่งเริ่มต้นที่เหมาะสมทั้งหมด อีกครั้ง: ไม่มีตัวอย่างตัวอย่าง แต่ไม่มีข้อพิสูจน์

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

ทั้งหมดนี้ควรลดเวลาในการคำนวณของคุณลงอย่างมาก


1
ฉันคิดว่าคุณเข้าใจคำถามผิด! แม้ว่านี่จะเป็นแรงจูงใจเบื้องหลังคำถาม คำถามคือการหาจำนวนขั้นต่ำของการย้ายเพื่อย้ายชิ้นเดียวไปยังตำแหน่งเดียว คำถามไม่ได้ที่จะหาจำนวนขั้นต่ำของการเคลื่อนไหวเพื่อจัดเรียงสแต็คแม้ว่าจะเป็นแรงจูงใจที่อยู่เบื้องหลังคำถาม อย่างไรก็ตามด้วยการให้คะแนนของ P คุณจะไม่ถูกต้อง มีหลายกรณีที่มี "การเคลื่อนไหวที่ไม่ดี" ที่จบลงด้วยการเพิ่ม P ในตอนแรกและจากนั้นจะลดลงในอัตราที่เร็วกว่า ด้วยที่กล่าวว่าอาจจะอ่านคำถามอีกครั้งเป็นคำตอบของคุณไม่มีความเกี่ยวข้อง
Tristen

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