Tower of Hanoi Representation - python

I'm having trouble implementing the problem in python as follows. I understand the original Tower of Hanoi problem which is that one can move $N$ disks to say the 3rd disk, and there are algorithms to do so but I am unable to figure out how to list out each of the individual disks at each stage. The problem is as follows:
I figured that I could use a binomial tree representation shown as follows:
So far the rough skeleton code I thought of would look something along the lines of
def recursion(m,n,T):
pos = list(range(1,m))
index = 0
values = list(range(1,n))
tree = []
if pos[index+1] > pos[index]:
pos[index + 1] -= pos[index+1]
pos[index + 2] += pos[index+1]
tree.append(pos)
if pos[index+1] < pos[index]:
pos[index+1] += pos[index]
pos[index] -= pos[index]
tree.append(pos)
else:
recursion()
return tree
I would greatly appreciate some help with this

You didn't pass no. of disks to your function, and this number must be decreased at every next call you make to the function. And there is a condition to break further recursion. Here is the modified form
# n = no. of rods
def recurse(n , from_rod, to_rod, aux_rod):
if n == 1:
print "Move disk 1 from rod", from_rod, "to rod",to_rod
return
recurse(n-1, from_rod, aux_rod, to_rod)
print "Move disk", n, "from rod", from, "to rod", to
recurse(n-1, aux_rod, to_rod, from_rod)
n = 5
recurse(n, 'A', 'B', 'C')

This is very similar to ksai solution except this is for python 3 and I removed the extra print and return statement
def move(disk , from_rod, to_rod, aux_rod):
if disk >= 1:
move(disk-1, from_rod, aux_rod, to_rod)
print ("Move disk", disk, "from rod", from_rod, "to rod", to_rod)
move(disk-1, aux_rod, to_rod, from_rod)
n = 3
move(n, 'A', 'B', 'C')
output:

Related

Facebook / Meta Coding Puzzle -- Rotary Lock (Chapter 2)

coding challenge screenshot
This is from Facebook/Meta Careers page practice problems
here is my current solution so far 2/32 test cases passed, has anyone been able to get 32/32?
from typing import List
# Write any import statements here
def getMinCodeEntryTime(N: int, M: int, C: List[int]) -> int:
# Write your code here
dial_1 = 1
dial_2 = 1
count = 0
code = C
if len(code) > 0:
for number in code:
print("before: dial_1, dial_2: ", dial_1, dial_2)
fwd_1 = abs(number - dial_1)
rev_1 = N - abs(number - dial_1)
fwd_2 = abs(number - dial_2)
rev_2 = N - abs(number - dial_2)
# Dial 1 calc: fwd vs rev
if fwd_1 > rev_1:
count_1 = rev_1
else:
count_1 = fwd_1
# Dial 2 calc: fwd vs rev
if fwd_2 > rev_2:
count_2 = rev_2
else:
count_2 = fwd_2
# Dial 1 vs Dial 2 movement decision
if count_1 > count_2:
dial_2 = number
count += count_2
else:
dial_1 = number
count += count_1
print("after: dial_1, dial_2: ", dial_1, dial_2, "+/-", count)
return count
Your algorithm is greedy. You always move the closest deal to the next number. Sometimes, you have to make a suboptimal move to get the best overall answer. (There are times greedy algorithms are optimal, but not here.)
Try writing a recursive function:best(n, other) gives you the number of moves to solve steps numbers Cn+1 to the end, assuming the two dials are at Cn and other. This will be a nice recursive function. Now rewrite the recursion in terms of dynamic programming.
Please don't expect anyone to write the code for you.

Project Euler Project 67 - Python

I am doing the Project Euler #67 in Python. My program, which worked for Project 18, does not work for Project 67.
Code (excludes the opening of the file and the processing of information):
for i in range(len(temp)):
list1 = temp[i]
try:
list2 = temp[i+1]
trynum1 = list1[lastinput] + max(list2[lastinput],list2[lastinput+1])
try:
trynum2 = list1[lastinput+1] + max(list2[lastinput+1],list2[lastinput+2])
if trynum1 > trynum2:
outputlist.append(list1[lastinput])
else:
outputlist.append(list1[lastinput+1])
lastinput += 1
except IndexError:
outputlist.append(list1[0])
except IndexError:
if list1[lastinput] > list1[lastinput+1]:
outputlist.append(list1[lastinput])
else:
outputlist.append(list1[lastinput+1])
Variables:
temp is the triangle of integers
outputlist is a list which stores the numbers chosen by the program
I know the answer is 7273, but my program finds 6542. I cannot find an error which causes the situation. Please may you help me on it.
Logic
My approach to this program is to find one number (list1[lastinput]) and add it up with the larger number of the two below it (trynum1), compare with the number to the right of the first number (list1[lastinput+1]), adding the larger number of two below it (trynum2). I append the larger one to the output list.
This approach is logically flawed. When you're in row 1, you don't have enough information to know whether moving right or left will lead you to the largest sum, not with only a 2-row lookahead. You would need to look all the way to the bottom to ensure getting the best path.
As others have suggested, start at the bottom and work up. Remember, you don't need the entire path, just the sum. At each node, add the amount of the better of the two available paths (that's the score you get in taking that node to the bottom). When you get back to the top, temp[0][0], that number should be your final answer.
I thought day and night about problem 18 and I solved it, the same way I solved this one.
P.S. 100_triangle.txt is without 1st string '59'.
# Maximum path sum II
import time
def e67():
start = time.time()
f=open("100_triangle.txt")
summ=[59]
for s in f:
slst=s.split()
lst=[int(item) for item in slst]
for i in range(len(lst)):
if i==0:
lst[i]+=summ[i]
elif i==len(lst)-1:
lst[i]+=summ[i-1]
elif (lst[i]+summ[i-1])>(lst[i]+summ[i]):
lst[i]+=summ[i-1]
else:
lst[i]+=summ[i]
summ=lst
end = time.time() - start
print("Runtime =", end)
f.close()
return max(summ)
print(e67()) #7273
Though starting from the bottom is more efficient, I wanted to see if I could implement Dijkstra's algorithm on this one; it works well and only takes a few seconds (didn't time it precisely):
from math import inf
f = open("p067_triangle.txt", "r")
tpyramid = f.read().splitlines()
f.close()
n = len(tpyramid)
pyramid = [[100 - int(tpyramid[i].split()[j]) for j in range(i+1)] for i in range(n)]
paths = [[inf for j in range(i+1)] for i in range(n)]
paths[0][0] = pyramid[0][0]
def mini_index(pyr):
m = inf
for i in range(n):
mr = min([i for i in pyr[i] if i >= 0]+[inf])
if mr < m:
m, a, b = mr, i, pyr[i].index(mr)
return m, a, b
counter = 0
omega = inf
while counter < n*(n+1)/2:
min_weight, i, j = mini_index(paths)
if i != n-1:
paths[i+1][j] = min( paths[i+1][j], min_weight + pyramid[i+1][j])
paths[i+1][j+1] = min( paths[i+1][j+1], min_weight + pyramid[i+1][j+1])
else:
omega = min(omega, min_weight)
paths[i][j] = -1
counter += 1
print(100*n - omega)
Here is my solution. Indeed you have to take the bottom - up approach.
Result confirmed with PE. Thanks!
def get_triangle(listLink):
triangle = [[int(number) for number in row.split()] for row in open(listLink)]
return triangle
listOfLists = get_triangle('D:\\Development\\triangle.txt')
for i in range(len(listOfLists) - 2, -1, -1):
for j in range(len(listOfLists[i])):
listOfLists[i][j] += max(listOfLists[i+1][j], listOfLists[i+1][j+1])
print(listOfLists[0][0])

What's wrong with my recursion implementation?

I have recently started learning programming, just completed a course on edX. I was trying to solve this problem on HackerRank and it is running out of time in each case. What am I doing wrong?
n,k = input().strip().split(' ')
n,k = [int(n),int(k)]
x = [int(x_temp) for x_temp in input().strip().split(' ')]
x.sort()
def transmitter(aList=[], target=0):
'''
accepts a list of house location, and a target location for the transmitter
returns the optimal number of transmitters required to cover all the houses
'''
List = aList[:]
start = target - k
end = target + k + 1
for i in range(start, end):
if i in List:
List.remove(i)
if not List:
return 1
m = max(List)
for e in List:
if transmitter(List, e) < m:
m = transmitter(List, e)
return 1 + m
m = max(x)
for e in x:
if transmitter(x, e) < m:
m = transmitter(x, e)
print(m)
I am pretty new to this. Sorry for making any obvious mistakes, or for posting this here in case this is not the suitable site. In that case, it will be really helpful if you can recommend a site where I can ask such question.
the screenshot of the question
I'm pretty sure a greedy algorithm solves this problem optimally in just O(N) time. There's not need for any recursion. Just place each transmitter in turn as far to the right as you can without leaving any houses to its left uncovered. Stop when the last house is covered.
Here's how I'd code that:
def hackerland(houses, k): # houses should be sorted list of locations
first = None # location of first uncovered house
last = 0 # last location covered by a previous transmitter
prev = None
count = 0 # transmitters = []
for x in houses:
if first is not None and x > first + k:
first = None
count += 1 # transmitters.append(prev)
last = prev + k
if last is not None and x > last:
last = None
first = x
prev = x
if first is not None:
count += 1 # transmitters.append(prev)
return count # return transmitters
I've included comments that show how this code could be easily modified to return a list of the transmitter locations, rather than just a count of how many are needed.
It is not necessary to take a recursive approach. In fact, you can just work forward, iterate over the houses, placing transmitters when the previously placed one does not reach far enough to cover the current house, etc.
It is a bit more complicated than that, but not much. See this code:
# input
n,k = input().strip().split(' ')
n,k = [int(n),int(k)]
x = [int(x_temp) for x_temp in input().strip().split(' ')]
# eliminate duplicate house x-xoordinates, they don't influence the result
houses = list(set(x))
houses.sort()
# add extreme far dummy house (will make the loop easier)
houses.append(100000)
reachedX = 0 # coordinate until where the previously placed transmitter reaches
unreachedX = -1 # coordinate that the next one needs to cover (to the left)
lastHouseId = -1 # index where previous transmitter was placed
transmitters = [] # coordinates of the placed transmitters
for houseId, houseX in enumerate(houses):
if reachedX > unreachedX: # we might still be in range of last transmitter
if houseX > reachedX: # we just went out of reach
unreachedX = houseX # this house must be covered by next one
elif houseX - k > unreachedX: # transmitter here wouldn't reach far enough back
lastHouseId = houseId - 1 # place it on previous house
reachedX = houses[lastHouseId] + k
transmitters.append(houses[lastHouseId])
print(transmitters)
print(len(transmitters))

Correct implementation of determining position in the list

I have a list of favourite movies and I'd like to sort them according to my taste from the best movies (have most points) to worst movie (has only 1 point).
Lets say the list contains already 300 sorted movies and you want to determine points for the new movie. You could compare the new movie with every movie in the sorted list or you can utilize the knowledge that the list is sorted.
I tried to implement it as a binary search so every insert (of new movie) has logarithmic complexity.
The binary search implementation was easy for me:
def binSearch(lst, number):
left = 0
right = len(lst) - 1
while left <= right:
middle = left + ((right - left) / 2)
if number == lst[middle]:
return True
else:
if number < lst[middle]:
right = middle - 1
else:
left = middle + 1
return False
But determining points is quite difficult for me. I'm already debugging it for a few hours and still some errors occur. I changed the implementation many times but nothing helps.
Here is my last solution (maybe the algorithm is in the worse state then it was at the beginning)
def determinePoints(lst, new):
# lst is a list of tuples with movies
# new is a tuple with new movie (has no point associated yet)
if not lst: # no movie has points so far
return 1 # now exists only one movie with associated points
newTitle = new[0]
newGenre = new[1]
atMost = len(lst)
atLeast = 0
while atLeast < atMost - 1: # algorithm doesn't work
# if only two movies have associated points
center = twoPointsCenter(atLeast, atMost)
(title, genre) = lst[center]
os.system("clear")
competitionStrings = [ newTitle, newGenre, "\n" * 10, title, genre ]
print "\n".join([ x.center(150) for x in competitionStrings ])
c = getch()
if c == "j": # new movie is worse than this
atMost = center - 1
if atMost <= 1:
return 1
else: # new movie is better than this
atLeast = center + 1
if atLeast >= len(lst):
return max(atLeast, 1)
return max(twoPointsCenter(atLeast, atMost), 1)
def twoPointsCenter(left, right):
return left + ((right - left) / 2)
Could you correct my solution (or implement it better) to converge and end with the right result?
It should work with lst of lengths from 0, 1, 2, ... etc. It shouldn't return value less than 1. In the list of movies there shouldn't be two movies with the same number of points.
When the function determinePoints returns points, I will update the database for this movie and increment points by 1 for each movie with >= points than this new movie.
Thank you
I think you need to better look at the boundary indexes. len(lst) is one larger than the maximal index, for example: lists are 0-based. I took the liberty to use 0 as lowest possible score; this will directly give you the position to lst.insert at. Also, I couldn't resist and made this a little more PEP 8-like.
You don't need all the corner cases; they just work fine, I think.
def determine_points(lst, new):
# lst is a list of tuples with movies, ranked by how good the movie is
# new is a tuple with new movie
# the new movies position is to be determined
new_title, new_genre = new
at_most = len(lst)
at_least = 0
while at_least < at_most:
center = (at_least + at_most) // 2
title, genre = lst[center]
os.system("clear")
competition_strings = [new_title, new_genre, "\n" * 10, title, genre]
print("\n".join(x.center(150) for x in competition_strings))
c = getch()
if c == "j": # new movie is worse than this
at_most = center
else: # new movie is better than this
at_least = center + 1
return at_least
Edit: I tested with the following code.
lst = []
news = [(str(i), str(i)) for i in range(10)]
import random
random.shuffle(news)
for new in news:
print(lst)
lst.insert(determine_points(lst, new), new)
print(lst)

Summing the number of instances a string is generated in iteration

Working in python 2.7.
I'm trying to work my way up to plotting a random walk. But first I'm having some trouble summing the number of results I get from a random generator.
The first piece of code:
def random_pick(some_list, probabilities):
x = random.uniform(0,1)
cumulative_probability = 0.0
for item, item_probability in zip(some_list, probabilities):
cumulative_probability += item_probability
if x < cumulative_probability: break
return item
In this case, the list is a = ['Hit', 'Out'] and the respective probabilities are given by b = [.3, .7]. This code returns 'Hit' with probability .3 and 'Out' with probability .7.
I then have code to create a rough sim of a player's batting average based on those probabilities:
def battingAverage(atBats, i, some_list=a, probabilities=b):
for i in range(1,atBats):
if random_pick(a, b) == 'Hit':
hit = random_pick(a, b)
print '%.0f: %s' % (1, 'Hit')
elif random_pick(a, b) == 'Out':
out = random_pick(a, b)
print '%.0f: %s' % (2, 'Out')
When I run this, I get a random generation of as many at-bats as a I choose. But I would like to be able to then sum the number of instances or both hit and out, but I have not been able to figure out how. I've tried to use code similar to below after changing the random_pick to return the probability instead of the item, but to no avail.
def battingAverage(atBats, i, some_list=a, probabilities=b):
num_hits = 0
num_outs = 0
for i in range(1,atBats):
if random_pick(a, b) == 'Hit':
hit = (random_pick(a, b))/.3
num_hits += hit
elif random_pick(a, b) == 'Out':
out = (random_pick(a, b))/7
num_outs += out
print num_hits, num_outs
Any help would be greatly appreciated. Also, does anyone know of a good resource to learn Monte Carlo simulations?
num_hits = 0
num_outs = 0
for i in range(1, atBats):
if random_pick(a,b) == 'Hit':
num_hits += 1
else:
num_outs += 1
print num_hits, num_outs
To be honest, I am struggling to follow the logic of your code (it's been a long day), but here are a couple of pointers:
1) When you do things like:
if random_pick(a, b) == 'Hit':
...
elif random_pick(a, b) == 'Out':
...
you're calling random_pick() twice, so you're conducting two independent simulations instead of one. As a result, it could be that neither of the two branches get executed. To fix, call random_pick() once, store the result, and then branch on that result.
2) As to your other problem, Python allows you to return multiple values from a function. This might be useful here:
def random_pick(some_list, probabilities):
... decide on the item and probability ...
return item, probability
You can then call it like so:
item, prob = random_pick(a, b)
and use item or prob (or both).

Categories

Resources