পাইথন: 1,688,293 1,579,182 1,524,054 1,450,842 1,093,195 চাল
মূল পদ্ধতিটি হ'ল main_to_help_best
যা কিছু নির্বাচিত উপাদানগুলি প্রধান স্ট্যাক থেকে সহায়ক সহায়কগুলিতে সরিয়ে নিয়ে যায়। everything
এটিতে একটি পতাকা রয়েছে যা সংজ্ঞায়িত করে যে আমরা এটি নির্দিষ্ট করে সমস্ত কিছু স্থানান্তরিত করতে চাই destination
, বা আমরা কেবল বৃহত্তম বৃহত্তম রাখতে চাইdestination
অন্য সহায়তায় থাকা অবস্থায় ।
মনে করুন আমরা dst
সাহায্যকারী ব্যবহার করতে চলেছি helper
, ফাংশনটি মোটামুটি নীচে বর্ণিত হতে পারে:
- বৃহত্তম উপাদানগুলির অবস্থান সন্ধান করুন
- সবকিছুকে সর্বাধিক বৃহত্তম এলিমেন্টের শীর্ষে নিয়ে যান
helper
পুনরাবৃত্তির
- বৃহত্তম উপাদান এ সরান
dst
helper
প্রধান থেকে পিছনে ধাক্কা
- বৃহত্তম উপাদানগুলি না হওয়া পর্যন্ত 2-4 পুনরাবৃত্তি করুন
dst
- ক। যদি
everything
সেট করা থাকে, পুনরাবৃত্তভাবে উপাদানগুলিকে প্রধানতে বিতে সরান dst
। অন্যথায়, পুনরাবৃত্তভাবে উপাদানগুলিকে প্রধানতে সরানhelper
প্রধান সাজানোর আলগোরিদিম ( sort2
আমার কোডে) তাহলে ডাকব main_to_help_best
সঙ্গে everything
সেটFalse
, এবং তারপর প্রধান বৃহত্তম উপাদান পিছান, তারপর প্রধান করার সাহায্যকারী পিছন থেকে সবকিছু সরানো, এটা সাজানো রাখা।
কোডে মন্তব্য হিসাবে এম্বেড করা আরও ব্যাখ্যা।
মূলত আমি যে নীতিগুলি ব্যবহার করি তা হ'ল:
- সর্বাধিক উপাদান (গুলি) রাখতে একজন সহায়ক রাখুন
- অন্য কোনও উপাদান থাকতে অন্য সহায়ককে রাখুন
- যতটা সম্ভব অপ্রয়োজনীয় চালচলন করবেন না
নীতি 3টি যদি পূর্ববর্তী গন্তব্য হয় তবে চলন গণনা না করে বাস্তবায়ন করা হয় (যেমন, আমরা কেবলমাত্র 1 হেপল 1 এ চলে এসেছি, তারপর আমরা হেল্প 1 থেকে হেল্প 2 এ যেতে চাই) এবং আরও, আমরা যদি আন্দোলনের সংখ্যা 1 দ্বারা হ্রাস করি তবে আমরা এটিকে মূল অবস্থানে ফিরিয়ে নিয়ে যাচ্ছেন (অর্থাত্ প্রধান থেকে হেল্প 1 তারপর হেল্প 1 প্রধান থেকে)। এছাড়াও, যদি পূর্ববর্তী n
চালগুলি সমস্ত একই সংখ্যার চলমান হয়, আমরা আসলে সেই n
পদক্ষেপগুলি পুনর্বিন্যাস করতে পারি । সুতরাং আমরা আরও এগিয়ে চলার সংখ্যা হ্রাস করতে যে সুবিধা গ্রহণ করি।
এটি বৈধ যেহেতু আমরা মূল স্ট্যাকের সমস্ত উপাদান জানি, তাই ভবিষ্যতে দেখে বোঝা যায় যে আমরা উপাদানটিকে পিছনে নিয়ে যাচ্ছি, আমাদের এই পদক্ষেপ নেওয়া উচিত নয়।
নমুনা রান (স্ট্যাকগুলি নীচে থেকে উপরে প্রদর্শিত হয় - তাই প্রথম উপাদানটি নীচে থাকে):
দৈর্ঘ্য 1
পদক্ষেপ: 0
কার্য: 6
সর্বাধিক: 0 ([1])
গড়: 0.000
দৈর্ঘ্য 2
চাল: 60
কার্য: 36
সর্বোচ্চ: 4 ([1, 2])
গড়: 1.667
দৈর্ঘ্য 3
চাল: 1030
কার্য: 216
সর্বাধিক: 9 ([2, 3, 1])
গড়: 4.769
দৈর্ঘ্য 4
চাল: 11765 7
কার্য: 1296
সর্বোচ্চ: 19 ([3, 4, 2, 1])
গড়: 9.078
দৈর্ঘ্য 5
পদক্ষেপ: 112325 25
কার্য: 7776
সর্বাধিক: 33 ([4, 5, 3, 2, 1])
গড়: 14.445
দৈর্ঘ্য 6
চাল: 968015
কার্য: 46656
সর্বাধিক: 51 ([5, 6, 4, 3, 2, 1])
গড়: 20.748
--------------
সার্বিক
পদক্ষেপ: 1093195
টাস্ক: 55986
গড়: 19.526
আমরা দেখতে পাচ্ছি যে সবচেয়ে বড় পরিস্থিতিটি যখন সবচেয়ে বড় উপাদানটি দ্বিতীয় তলায় রাখা হয়, যখন বাকীগুলি বাছাই করা হয়। সবচেয়ে খারাপ পরিস্থিতি থেকে আমরা দেখতে পাই যে অ্যালগরিদমটি হ'ল (এন ^ 2)।
পদক্ষেপের সংখ্যা অবশ্যই এর জন্য ন্যূনতম n=1
এবং ফলাফল n=2
হিসাবে আমরা দেখতে পাচ্ছি এবং আমি বিশ্বাস করি এটি বৃহত্তর মূল্যবোধের জন্যও ন্যূনতম n
, যদিও আমি এটি প্রমাণ করতে পারি না।
আরও ব্যাখ্যা কোডে রয়েছে।
from itertools import product
DEBUG = False
def sort_better(main, help1, help2):
# Offset denotes the bottom-most position which is incorrect
offset = len(main)
ref = list(reversed(sorted(main)))
for idx, ref_el, real_el in zip(range(len(main)), ref, main):
if ref_el != real_el:
offset = idx
break
num_moves = 0
# Move the largest to help1, the rest to help2
num_moves += main_to_help_best(main, help1, help2, offset, False)
# Move the largest back to main
num_moves += push_to_main(help1, main)
# Move everything (sorted in help2) back to main, keep it sorted
num_moves += move_to_main(help2, main, help1)
return num_moves
def main_to_help_best(main, dst, helper, offset, everything=True):
"""
Moves everything to dst if everything is true,
otherwise move only the largest to dst, and the rest to helper
"""
if offset >= len(main):
return 0
max_el = -10**10
max_idx = -1
# Find the location of the top-most largest element
for idx, el in enumerate(main[offset:]):
if el >= max_el:
max_idx = idx+offset
max_el = el
num_moves = 0
# Loop from that position downwards
for max_idx in range(max_idx, offset-1, -1):
# Processing only at positions with largest element
if main[max_idx] < max_el:
continue
# The number of elements above this largest element
top_count = len(main)-max_idx-1
# Move everything above this largest element to helper
num_moves += main_to_help_best(main, helper, dst, max_idx+1)
# Move the largest to dst
num_moves += move(main, dst)
# Move back the top elements
num_moves += push_to_main(helper, main, top_count)
# Here, the largest elements are in dst, the rest are in main, not sorted
if everything:
# Move everything to dst on top of the largest
num_moves += main_to_help_best(main, dst, helper, offset)
else:
# Move everything to helper, not with the largest
num_moves += main_to_help_best(main, helper, dst, offset)
return num_moves
def verify(lst, moves):
if len(moves) == 1:
return True
moves[1][0][:] = lst
for src, dst, el in moves[1:]:
move(src, dst)
return True
def equal(*args):
return len(set(str(arg.__init__) for arg in args))==1
def move(src, dst):
dst.append(src.pop())
el = dst[-1]
if not equal(dst, sort.lst) and list(reversed(sorted(dst))) != dst:
raise Exception('HELPER NOT SORTED: %s, %s' % (src, dst))
cur_len = len(move.history)
check_idx = -1
matched = False
prev_src, prev_dst, prev_el = move.history[check_idx]
# As long as the element is the same as previous elements,
# we can reorder the moves
while el == prev_el:
if equal(src, prev_dst) and equal(dst, prev_src):
del(move.history[check_idx])
matched = True
break
elif equal(src, prev_dst):
move.history[check_idx][1] = dst
matched = True
break
elif equal(dst, prev_src):
move.history[check_idx][0] = src
matched = True
break
check_idx -= 1
prev_src, prev_dst, prev_el = move.history[check_idx]
if not matched:
move.history.append([src, dst, el])
return len(move.history)-cur_len
def push_to_main(src, main, amount=-1):
num_moves = 0
if amount == -1:
amount = len(src)
if amount == 0:
return 0
for i in range(amount):
num_moves += move(src, main)
return num_moves
def push_to_help(main, dst, amount=-1):
num_moves = 0
if amount == -1:
amount = len(main)
if amount == 0:
return 0
for i in range(amount):
num_moves += move(main, dst)
return num_moves
def help_to_help(src, dst, main, amount=-1):
num_moves = 0
if amount == -1:
amount = len(src)
if amount == 0:
return 0
# Count the number of largest elements
src_len = len(src)
base_el = src[src_len-amount]
base_idx = src_len-amount+1
while base_idx < src_len and base_el == src[base_idx]:
base_idx += 1
# Move elements which are not the largest to main
num_moves += push_to_main(src, main, src_len-base_idx)
# Move the largest to destination
num_moves += push_to_help(src, dst, base_idx+amount-src_len)
# Move back from main
num_moves += push_to_help(main, dst, src_len-base_idx)
return num_moves
def move_to_main(src, main, helper, amount=-1):
num_moves = 0
if amount == -1:
amount = len(src)
if amount == 0:
return 0
# Count the number of largest elements
src_len = len(src)
base_el = src[src_len-amount]
base_idx = src_len-amount+1
while base_idx < src_len and base_el == src[base_idx]:
base_idx += 1
# Move elements which are not the largest to helper
num_moves += help_to_help(src, helper, main, src_len-base_idx)
# Move the largest to main
num_moves += push_to_main(src, main, base_idx+amount-src_len)
# Repeat for the rest of the elements now in the other helper
num_moves += move_to_main(helper, main, src, src_len-base_idx)
return num_moves
def main():
num_tasks = 0
num_moves = 0
for n in range(1, 7):
start_moves = num_moves
start_tasks = num_tasks
max_move = -1
max_main = []
for lst in map(list,product(*[[1,2,3,4,5,6]]*n)):
num_tasks += 1
if DEBUG: print lst, [], []
sort.lst = lst
cur_lst = lst[:]
move.history = [(None, None, None)]
help1 = []
help2 = []
moves = sort_better(lst, help1, help2)
if moves > max_move:
max_move = moves
max_main = cur_lst
num_moves += moves
if DEBUG: print '%s, %s, %s (moves: %d)' % (cur_lst, [], [], moves)
if list(reversed(sorted(lst))) != lst:
print 'NOT SORTED: %s' % lst
return
if DEBUG: print
# Verify that the modified list of moves is still valid
verify(cur_lst, move.history)
end_moves = num_moves - start_moves
end_tasks = num_tasks - start_tasks
print 'Length %d\nMoves: %d\nTasks: %d\nMax: %d (%s)\nAverage: %.3f\n' % (n, end_moves, end_tasks, max_move, max_main, 1.0*end_moves/end_tasks)
print '--------------'
print 'Overall\nMoves: %d\nTasks: %d\nAverage: %.3f' % (num_moves, num_tasks, 1.0*num_moves/num_tasks)
# Old sort method, which assumes we can only see the top of the stack
def sort(main, max_stack, a_stack):
height = len(main)
largest = -1
num_moves = 0
a_stack_second_el = 10**10
for i in range(height):
if len(main)==0:
break
el = main[-1]
if el > largest: # We found a new maximum element
if i < height-1: # Process only if it is not at the bottom of main stack
largest = el
if len(a_stack)>0 and a_stack[-1] < max_stack[-1] < a_stack_second_el:
a_stack_second_el = max_stack[-1]
# Move aux stack to max stack then reverse the role
num_moves += help_to_help(a_stack, max_stack, main)
max_stack, a_stack = a_stack, max_stack
if DEBUG: print 'Moved max_stack to a_stack: %s, %s, %s (moves: %d)' % (main, max_stack, a_stack, num_moves)
num_moves += move(main, max_stack)
if DEBUG: print 'Moved el to max_stack: %s, %s, %s (moves: %d)' % (main, max_stack, a_stack, num_moves)
elif el == largest:
# The maximum element is the same as in max stack, append
if i < height-1: # Only if the maximum element is not at the bottom
num_moves += move(main, max_stack)
elif len(a_stack)==0 or el <= a_stack[-1]:
# Current element is the same as in aux stack, append
if len(a_stack)>0 and el < a_stack[-1]:
a_stack_second_el = a_stack[-1]
num_moves += move(main, a_stack)
elif a_stack[-1] < el <= a_stack_second_el:
# Current element is larger, but smaller than the next largest element
# Step 1
# Move the smallest element(s) in aux stack into max stack
amount = 0
while len(a_stack)>0 and a_stack[-1] != a_stack_second_el:
num_moves += move(a_stack, max_stack)
amount += 1
# Step 2
# Move all elements in main stack that is between the smallest
# element in aux stack and current element
while len(main)>0 and max_stack[-1] <= main[-1] <= el:
if max_stack[-1] < main[-1] < a_stack_second_el:
a_stack_second_el = main[-1]
num_moves += move(main, a_stack)
el = a_stack[-1]
# Step 3
# Put the smallest element(s) back
for i in range(amount):
num_moves += move(max_stack, a_stack)
else: # Find a location in aux stack to put current element
# Step 1
# Move all elements into max stack as long as it will still
# fulfill the Hanoi condition on max stack, AND
# it should be greater than the smallest element in aux stack
# So that we won't duplicate work, because in Step 2 we want
# the main stack to contain the minimum element
while len(main)>0 and a_stack[-1] < main[-1] <= max_stack[-1]:
num_moves += move(main, max_stack)
# Step 2
# Pick the minimum between max stack and aux stack, move to main
# This will essentially sort (in reverse) the elements into main
# Don't move to main the element(s) found before Step 1, because
# we want to move them to aux stack
while True:
if len(a_stack)>0 and a_stack[-1] < max_stack[-1]:
num_moves += move(a_stack, main)
elif max_stack[-1] < el:
num_moves += move(max_stack, main)
else:
break
# Step 3
# Move all elements in main into aux stack, as long as it
# satisfies the Hanoi condition on aux stack
while max_stack[-1] == el:
num_moves += move(max_stack, a_stack)
while len(main)>0 and main[-1] <= a_stack[-1]:
if main[-1] < a_stack[-1] < a_stack_second_el:
a_stack_second_el = a_stack[-1]
num_moves += move(main, a_stack)
if DEBUG: print main, max_stack, a_stack
# Now max stack contains largest element(s), aux stack the rest
num_moves += push_to_main(max_stack, main)
num_moves += move_to_main(a_stack, main, max_stack)
return num_moves
if __name__ == '__main__':
main()