N이 스택 수이고 P가 스택 용량 인 NXP 스택 세트를 가정하면 위치 A의 일부 노드에서 임의의 위치 B로 이동하는 데 필요한 최소 스왑 수를 어떻게 계산할 수 있습니까? 저는 게임을 디자인하고 있으며 최종 목표는 모든 스택을 모두 같은 색으로 정렬하는 것입니다.
# 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의 알고리즘을 실행하려고했습니다. . 실망스럽게 보이지만 지수 시간 이외의 다른 방법으로 실행할 수있는 방법을 알 수 없습니다. 여기에 적용 가능한 누락 된 알고리즘이 있습니까?
편집하다
필요한 최소 이동 수를 계산하기 위해이 함수를 작성했습니다. stacks : 스택의 조각을 나타내는 문자 목록, stacks [0] [0]은 스택의 맨 위 [0] stack_ind : 조각이 needs_piece에 추가 될 스택 : 스택에 추가되어야하는 조각 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의 사례와 같은 사례 수를 최소화 할 수있는 방법이 있습니다. 이 문제에 대한 나의 가장 최근의 접근법은 위에서 언급 한 것과 유사한 일련의 규칙을 개발하고이를 세대 알고리즘으로 사용하는 것입니다.
다음과 같은 규칙 :
이동을 되 돌리지 마십시오. 1-> 0에서 0-> 1로 이동하십시오.
조각을 연속으로 두 번 움직이지 마십시오. 0-> 1에서 1-> 3으로 이동하지 마십시오.
스택 [X]에서 스택 [Y]으로 약간의 이동이 주어진 경우, 스택 [Z]가 이동했을 때와 동일한 상태에있는 경우 약간의 이동, 스택 [Y]에서 스택 [Z]으로 이동 스택 [X]에서 스택 [Y]으로, 스택 [X]에서 스택 [Z]으로 직접 이동하여 이동을 제거 할 수있었습니다.
현재 충분한 규칙을 작성하여 "유효한"이동 수를 최소화하여 생성 알고리즘을 사용하여 답변을 계산할 수 있도록이 문제에 접근하고 있습니다. 누구나 추가 규칙을 생각할 수 있다면 의견을 듣고 싶습니다.
최신 정보
@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
목표 스택을 확인하면 먼저 다음이 발생합니다.
(0, 1), (0, 2), (1, 0), (2, 0) = 4 Moves
목표 스택 무시하기 :
(1, 0), (1, 2), (0, 1), (0, 1), (2, 0) = 5 Moves