0% found this document useful (0 votes)
46 views

FIT1045 53 Workshop 11 Solutions FIT1045 53 Workshop 11 Solutions

This document provides solutions to an algorithms workshop covering greedy, brute force, and backtracking algorithms. It includes implementations of recursive bitlists and permutations, greedy and brute force coin exchange problems, and a backtracking coin exchange solution. Code examples are provided for each algorithm along with test cases and explanations of the approaches.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
46 views

FIT1045 53 Workshop 11 Solutions FIT1045 53 Workshop 11 Solutions

This document provides solutions to an algorithms workshop covering greedy, brute force, and backtracking algorithms. It includes implementations of recursive bitlists and permutations, greedy and brute force coin exchange problems, and a backtracking coin exchange solution. Code examples are provided for each algorithm along with test cases and explanations of the approaches.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 5

lOMoARcPSD|9314401

FIT1045 53 workshop 11 solutions

Introduction to Algorithm and Python (Monash University)

StuDocu is not sponsored or endorsed by any college or university


Downloaded by goodgamers99 gamers ([email protected])
lOMoARcPSD|9314401

FIT1045/1053 Algorithms and Programming Fundamentals in


Python – Workshop 11.
Solutions

Objectives
After this workshop, you should be able to:
❼ Implement Greedy, Brute Force and Backtracking algorithms.

❼ Write a solution that can order bitlists and permutations in lexicographical order.

Task 1: Brute Force, Bitlists and Lexicographic Order


The lecture introduced iterative (non-recursive) algorithms to generate all bitlists of length n and all permu-
tations of n elements in lexicographic order. Both algorithms, but especially the one for permutations appear
complicated. In this activity we explore how simpler implementations can be provided using recursion.

Warmup

def lex_less_eq (a , b ):
""" Determines whether sequence ( a ) is lexicographically less or equal to
sequence ( b ); equivalent to a <= b .

For example :
>>> lex_less_eq ( ✬ tactic ✬ , ✬ tree ✬ )
True
>>> lex_less_eq ( ✬ tactic ✬ , ✬ tactical display ✬ )
True
>>> lex_less_eq ([1 , 2 , 3] , [0 , 1 , 2 , 3])
False
"""
for i in range ( min ( len ( a ) , len ( b ))):
if a [ i ] != b [ i ]:
return a [ i ] < b [ i ]
return len ( a ) <= len ( b )

Part A: Recursive Bitlist

def rbitlists ( n ):
""" Generates list of all bitlists of length n in lexicographic order
using recursion .

For example .
>>> rbitlists (2)
[[0 , 0] , [0 , 1] , [1 , 0] , [1 , 1]]
>>> rbitlists (3)
[[0 , 0 , 0] , [0 , 0 , 1] , [0 , 1 , 0] , [0 , 1 , 1] , [1 , 0 , 0] , [1 , 0 , 1] , [1 , 1 , 0] , [1 ,

The implementation lists bitlists recursively from the base case


n ==0 where the solution only consists of the empty bitlist .
Recursively , the functions first generates all length n bitlists

1
Downloaded by goodgamers99 gamers ([email protected])
lOMoARcPSD|9314401

resulting from prepending 0 to all bitlists of length n -1 and


then all length n bitlists resulting from prepending 1 to all
biltists of length n -1.
The approach is correct because all the bitlists resulting from
prepending 0 are lexicographically smaller than those resulting from
prepending 1 ( and internally the length n -1 bitlists are ordered
lexicographically by correctness of the recursive call ).
"""
if n == 0:
return [[]]

lists = rbitlists (n -1)

return [[0] + lst for lst in lists ] + \


[[1] + lst for lst in lists ]
Part B: Recursive Permutations

def rpermutations ( lst ):


""" Generates all permutations of input list .

>>> sorted ( rpermutations ( list ( range (1 , 4))))


[[1 , 2 , 3] , [1 , 3 , 2] , [2 , 1 , 3] , [2 , 3 , 1] , [3 , 1 , 2] , [3 , 2 , 1]]
>>> sorted ( rpermutations ( list ( range (1 , 5))))
[[1 , 2 , 3 , 4] , [1 , 2 , 4 , 3] , [1 , 3 , 2 , 4] , [1 , 3 , 4 , 2] , [1 , 4 , 2 , 3] ,
[1 , 4 , 3 , 2] , [2 , 1 , 3 , 4] , [2 , 1 , 4 , 3] , [2 , 3 , 1 , 4] , [2 , 3 , 4 , 1] ,
[2 , 4 , 1 , 3] , [2 , 4 , 3 , 1] , [3 , 1 , 2 , 4] , [3 , 1 , 4 , 2] , [3 , 2 , 1 , 4] ,
[3 , 2 , 4 , 1] , [3 , 4 , 1 , 2] , [3 , 4 , 2 , 1] , [4 , 1 , 2 , 3] , [4 , 1 , 3 , 2] ,
[4 , 2 , 1 , 3] , [4 , 2 , 3 , 1] , [4 , 3 , 1 , 2] , [4 , 3 , 2 , 1]]
>>> sorted ( rpermutations ( list ( ✬ JOE ✬ )))
[[ ✬ E ✬ , ✬ J ✬ , ✬ O ✬ ] , [ ✬ E ✬ , ✬ O ✬ , ✬ J ✬ ] , [ ✬ J ✬ , ✬ E ✬ , ✬ O ✬ ] , [ ✬ J ✬ , ✬ O ✬ , ✬ E ✬ ] ,
[ ✬ O ✬ , ✬ E ✬ , ✬ J ✬ ] , [ ✬ O ✬ , ✬ J ✬ , ✬ E ✬ ]]

For the base case of an empty input list the only permutation is the
empty list itself . For non - empty lst , assuming that we can enumerate all
permutations of the sublist lst [: -1] ( all except last element ) , we can
then recursively generate a list of all permutations by inserting
the last element in all possible positions for each permutation of the
smaller list .
"""
if len ( lst )==0:
return [[]]

perms = rpermutations ( lst [: -1])


res = []
for perm in perms :
res += [ perm [: i ]+[ lst [ -1]]+ perm [ i :] for i in range ( len ( perm ) , -1 , -1)]
return res

Task 2: Coin Exchange Problem


Part A: Greedy Implementation

def greedy_exchange ( amount , denominations ):


"""
>>> greedy_exchange (56 , [20 , 10 , 5 , 1])
[2 , 1 , 1 , 1]
>>> greedy_exchange (350 , [100 , 50 , 10 , 5 , 2 , 1])
[3 , 1 , 0 , 0 , 0 , 0]
>>> greedy_exchange (12 , [9 , 6 , 5 , 1])
[1 , 0 , 0 , 3]

2
Downloaded by goodgamers99 gamers ([email protected])
lOMoARcPSD|9314401

"""
res = []
s = 0
for i in range ( len ( denominations )):
c = ( amount - s ) // denominations [ i ]
s += c * denominations [ i ]
res += [ c ]
return res if s == amount else None
Part B1: Bounded Lists
def lex_suc ( bitlist , upper_bounds ):
"""
Input : bitlist a !=[1 ,... ,1]
Output : direct lex . successor of a
"""
res = bitlist [:]
i = len ( res ) - 1
while res [ i ] == upper_bounds [ i ]:
res [ i ] = 0
i -= 1
res [ i ] += 1
return res

def bounded_lists ( upper_bounds ):


"""
Input : List of positive integers of length ✬ n ✬
Output : List of lists where i , lst [ i ] <= upper_bound [ i ]

>>> bounded_lists ([1 , 1 , 2])


[[0 , 0 , 0] , [0 , 0 , 1] , [0 , 0 , 2] , [0 , 1 , 0] , [0 , 1 , 1] , [0 , 1 , 2] , [1 , 0 , 0] , [1 ,
"""
first = len ( upper_bounds )*[0]
last = upper_bounds
res = [ first ]
while res [ -1] != last :
res += [ lex_suc ( res [ -1] , upper_bounds )]
return res
Part B2: Brute Force Implementation
def b r u t e _ f o r c e _ c o i n _ e x c ha n g e ( amount , denominations ):
"""
Input : The target amount of you want to reach and a list of
coins ( i . e . denominations ) that you have an infinite amount of .
Output : A list of integers where each index represents the number of
coins the denominations list .

>>> b r u t e _ f o r c e _ c oi n _ e x c h a n g e (15 , [10 , 7 , 6 , 1])


[0 , 2 , 0 , 1]
"""
def cost ( solution ):
return sum ( solution )

def is_feasible ( solution ):


total = 0
for i in range ( len ( solution )):
total += solution [ i ]* denominations [ i ]
return total == amount

upper_bounds = []
for denom in denominations :

3
Downloaded by goodgamers99 gamers ([email protected])
lOMoARcPSD|9314401

upper_bounds += [ amount // denom ]

sols = bounded_lists ( upper_bounds )


feasible = filter ( is_feasible , sols )
opt = min ( feasible , key = cost )
return opt
Part C: Backtracking Implementation

def solutions ( completed , options , part = []):


if completed ( part ):
return [ part ]
else :
res = []
for o in options ( part ):
augmented = part + [ o ]
res += solutions ( completed , options , augmented )
return res

def backt rack ing_ excha nge ( amount , denominations ):


"""
>>> ba cktr acki ng_ex chan ge (56 , [20 , 10 , 5 , 1])
[2 , 1 , 1 , 1]
>>> ba cktr acki ng_ex chan ge (12 , [9 , 6 , 5 , 1])
[0 , 2 , 0 , 0]
"""
n = len ( denominations )

def total ( part ):


return sum ( part [ i ]* denominations [ i ] for i in range ( len ( part )))

def complete ( part ):


return len ( part )== n and amount - total ( part ) == 0

def options ( part ):


if len ( part ) == n :
return []
else :
remaining = amount - total ( part )
max_coins = remaining // denominations [ len ( part )]
return reversed ( range ( max_coins + 1))

sols = solutions ( complete , options )

return min ( sols , key = sum , default = None )

4
Downloaded by goodgamers99 gamers ([email protected])

You might also like