Diberikan satu set tumpukan NXP dengan N menjadi jumlah tumpukan, dan P menjadi kapasitas tumpukan, bagaimana saya bisa menghitung jumlah minimum swap yang diperlukan untuk berpindah dari beberapa simpul di lokasi A ke beberapa lokasi acak B? Saya merancang sebuah game, dan tujuan akhirnya adalah menyortir semua tumpukan agar warnanya sama.
# 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']
]
Jika saya ingin memasukkan "B" di tempat stacks[1][1]
seperti itu stacks[1] = ["-", "B", "Y", "Y"]
. Bagaimana saya bisa menentukan jumlah minimum gerakan yang diperlukan untuk melakukannya?
Saya telah melihat beberapa pendekatan, saya telah mencoba algoritma genetika yang menghasilkan semua kemungkinan pergerakan dari keadaan, memberi skor, dan kemudian melanjutkan jalur skor terbaik, saya juga mencoba menjalankan algoritma Djikstra untuk merintis masalah. . Tampaknya sangat sederhana, namun saya tidak tahu cara untuk menjalankannya selain dari waktu eksponensial. Apakah ada algoritma yang saya lewatkan yang dapat diterapkan di sini?
Edit
Saya telah menulis fungsi ini untuk menghitung jumlah minimum gerakan yang diperlukan: tumpukan: Daftar Daftar Karakter yang mewakili potongan-potongan dalam tumpukan, tumpukan [0] [0] adalah bagian atas tumpukan [0] stack_ind: Indeks dari tumpukan potongan yang akan ditambahkan ke needs_piece: Potongan yang harus ditambahkan ke tumpukan needs_index: Indeks di mana potongan harus ditempatkan
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")
Sunting: Test Case pada tumpukan:
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
Implementasi kode yang sebenarnya bukan bagian yang sulit, itu menentukan cara mengimplementasikan algoritma yang memecahkan masalah yang saya perjuangkan.
Sesuai permintaan @ YonIif, saya telah membuat inti untuk masalah ini.
Ketika dijalankan, ini menghasilkan susunan acak tumpukan, dan memilih potongan acak yang perlu dimasukkan ke dalam tumpukan acak di lokasi acak.
Menjalankannya mencetak sesuatu dari format ini ke konsol.
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']
Pembaruan status
Saya sangat bertekad untuk menyelesaikan masalah ini entah bagaimana .
Perlu diingat bahwa ada cara untuk meminimalkan jumlah kasus, seperti yang @Hans Olsson disebutkan dalam komentar. Pendekatan terbaru saya untuk masalah ini, adalah mengembangkan seperangkat aturan yang mirip dengan yang disebutkan, dan mempekerjakan mereka dalam algoritma generasi.
Aturan seperti:
Jangan pernah membalikkan gerakan. Pergi dari 1-> 0 lalu 0-> 1 (Tidak masuk akal)
Jangan pernah memindahkan sepotong dua kali berturut-turut. Jangan Pindah dari 0 -> 1 lalu 1 -> 3
Diberikan beberapa perpindahan dari tumpukan [X] ke tumpukan [Y], kemudian beberapa perpindahan, kemudian perpindahan dari tumpukan [Y] ke tumpukan [Z], jika tumpukan [Z] berada dalam keadaan yang sama seperti ketika perpindahan dari tumpukan [X] ke tumpukan [Y] terjadi, suatu langkah bisa dihilangkan dengan pindah dari tumpukan [X] langsung ke tumpukan [Z]
Saat ini, saya mendekati masalah ini dengan upaya untuk membuat aturan yang cukup, sehingga meminimalkan jumlah gerakan "valid", cukup sehingga jawaban dapat dihitung menggunakan algoritma generasi. Jika ada yang bisa memikirkan aturan tambahan, saya akan tertarik mendengarnya di komentar.
Memperbarui
Berkat jawabannya oleh @RootTwo, saya sudah memiliki sedikit terobosan, yang akan saya uraikan di sini.
Ke terobosan
Tentukan tinggi gawang sebagai kedalaman potongan gawang harus ditempatkan di tumpukan tujuan.
Setiap kali bagian gawang ditempatkan pada indeks <= stack_height - tinggi gawang, akan selalu ada jalan terpendek menuju kemenangan melalui metode clear_path ().
Let S represent some solid Piece.
YAITU
Stacks = [ [R, R, G], [G, G, R], [-, -, -] ]
Goal = Stacks[0][2] = R
Goal Height = 2.
Stack Height - Goal Height = 0
Diberikan beberapa tumpukan sehingga stack[0] = R
, permainan dimenangkan.
GOAL
[ [ (S | -), (S | -), (S | -) ], [R, S, S], [(S | - ), (S | -), (S | -)] ]
Karena diketahui bahwa mereka selalu setidaknya ruang kosong stack_height tersedia, kasus terburuk yang mungkin terjadi adalah:
[ [ S, S, !Goal ], [R, S, S], [-, -, -]
Karena kita tahu bagian gawang tidak bisa berada di tujuan gawang atau permainan dimenangkan. Dalam hal ini jumlah gerakan minimum yang diperlukan adalah gerakan:
(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
Diberikan beberapa tumpukan sehingga stack[1] = R
, permainan dimenangkan.
GOAL
[ [ (S | -), (S | -), S], [ (S | -), R, S], [(S | -), (S | -), (S | -)]
Kami tahu setidaknya ada 3 ruang kosong yang tersedia, jadi kasus terburuk yang mungkin terjadi adalah:
[ [ S, !Goal, S], [S, R, S], [ -, -, - ]
Dalam hal ini jumlah gerakan minimum adalah gerakan:
(1, 2), (0, 2), (0, 2), (1, 0)
Ini akan berlaku untuk semua kasus.
Dengan demikian, masalahnya telah direduksi menjadi masalah menemukan jumlah minimum gerakan yang diperlukan untuk menempatkan potongan gawang pada atau di atas pada ketinggian gawang.
Ini membagi masalah menjadi serangkaian sub-masalah:
Ketika tumpukan tujuan memiliki bagian yang dapat diakses! = Bagian tujuan, menentukan apakah ada lokasi yang valid untuk potongan itu, atau apakah potongan itu harus tetap di sana saat potongan lain ditukar.
Ketika tumpukan tujuan memiliki bagian yang dapat diakses == bagian tujuan, menentukan apakah itu dapat dihapus dan ditempatkan pada ketinggian tujuan yang diperlukan, atau jika potongan harus tetap sementara yang lain ditukar.
Ketika kedua kasus di atas membutuhkan bagian yang lain untuk ditukar, tentukan bagian mana yang akan ditukar untuk meningkatkan agar bagian tujuan dapat mencapai ketinggian tujuan.
Tumpukan tujuan harus selalu dievaluasi kasusnya terlebih dahulu.
YAITU
stacks = [ [-, R, G], [-, R, G], [-, R, G] ]
Goal = stacks[0][1] = G
Memeriksa Goal Stack pertama-tama mengarah ke:
(0, 1), (0, 2), (1, 0), (2, 0) = 4 Moves
Mengabaikan Sasaran Sasaran:
(1, 0), (1, 2), (0, 1), (0, 1), (2, 0) = 5 Moves