├── README ├── countingsort.py ├── gcd.py ├── binary.py ├── permutations.py ├── insertionsort.py ├── selectionsort.py ├── maxpermutation.py ├── topsort.py ├── fibo.py ├── bmh.py ├── celebrityproblem.py ├── quicksort.py ├── mergesort.py ├── kmp.py ├── josephus.py ├── sieve1.py ├── trees.py ├── graphs.py ├── factorial.py ├── knapsack2.py └── knapsack.py /README: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /countingsort.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | def counting_sort(A, key=lambda x: x): 3 | B, C = [], defaultdict(list) 4 | for x in A: 5 | C[key(x)].append(x) 6 | for k in range(min(C), max(C)+1): 7 | B.extend(C[k]) 8 | return B 9 | -------------------------------------------------------------------------------- /gcd.py: -------------------------------------------------------------------------------- 1 | def gcd_rec(m, n): 2 | if m % n == 0: 3 | return n 4 | return gcd_rec(n, m %n) 5 | 6 | def gcd_iter(m, n): 7 | while m % n != 0: 8 | temp = n 9 | n = m % n 10 | m = temp 11 | return n 12 | 13 | if __name__ == '__main__': 14 | print gcd_rec(40, 10) 15 | print gcd_iter(40, 10) 16 | -------------------------------------------------------------------------------- /binary.py: -------------------------------------------------------------------------------- 1 | def binary(seq, x): 2 | l = 0 3 | r = len(seq) 4 | while l < r: 5 | m = (l + r) // 2 6 | if seq[m] < x: 7 | l = m + 1 8 | else: 9 | r = m 10 | if seq[l] == x: 11 | return l 12 | else: 13 | return -1 14 | 15 | if __name__ == '__main__': 16 | print binary([1,2,3,4,5,6,7,8], 10) 17 | -------------------------------------------------------------------------------- /permutations.py: -------------------------------------------------------------------------------- 1 | def all_perms(str): 2 | if len(str) <=1: 3 | yield str 4 | else: 5 | for perm in all_perms(str[1:]): 6 | for i in range(len(perm)+1): 7 | #nb str[0:1] works in both string and list contexts 8 | yield perm[:i] + str[0:1] + perm[i:] 9 | 10 | if __name__ == '__main__': 11 | for i in all_perms([1,2,3]): 12 | print i 13 | -------------------------------------------------------------------------------- /insertionsort.py: -------------------------------------------------------------------------------- 1 | def ins_sort_rec(seq, i): 2 | if i==0: return 3 | ins_sort_rec(seq, i-1) 4 | j = i 5 | while j > 0 and seq[j-1] > seq[j]: 6 | seq[j-1], seq[j] = seq[j], seq[j-1] 7 | j -= 1 8 | 9 | def ins_sort(seq): 10 | for i in range(1,len(seq)): 11 | j = i 12 | while j > 0 and seq[j-1] > seq[j]: 13 | seq[j-1], seq[j] = seq[j], seq[j-1] 14 | j -= 1 15 | -------------------------------------------------------------------------------- /selectionsort.py: -------------------------------------------------------------------------------- 1 | def sel_sort_rec(seq, i): 2 | if i==0: 3 | return 4 | max_j = i 5 | for j in range(i): 6 | if seq[j] > seq[max_j]: 7 | max_j = j 8 | seq[i], seq[max_j] = seq[max_j], seq[i] 9 | sel_sort_rec(seq, i-1) 10 | 11 | def sel_sort(seq): 12 | for i in range(len(seq)-1,0,-1): 13 | max_j = i 14 | for j in range(i): 15 | if seq[j] > seq[max_j]: max_j = j 16 | seq[i], seq[max_j] = seq[max_j], seq[i] 17 | 18 | -------------------------------------------------------------------------------- /maxpermutation.py: -------------------------------------------------------------------------------- 1 | def naive_max_perm(M, A=None): 2 | if A is None: 3 | A = set(range(len(M))) 4 | if len(A) == 1: return A 5 | B = set(M[i] for i in A) 6 | C = A - B 7 | if C: 8 | A.remove(C.pop()) 9 | return naive_max_perm(M, A) 10 | return A 11 | 12 | 13 | def max_perm(M): 14 | n = len(M) 15 | A = set(range(n)) 16 | count = [0]*n 17 | for i in M: 18 | count[i] += 1 19 | Q = [i for i in A if count[i] == 0] 20 | while Q: 21 | i = Q.pop() 22 | A.remove(i) 23 | j = M[i] 24 | count[j] -= 1 25 | if count[j] == 0: 26 | Q.append(j) 27 | return A 28 | -------------------------------------------------------------------------------- /topsort.py: -------------------------------------------------------------------------------- 1 | def naive_topsort(G, S=None): 2 | if S is None: S = set(G) 3 | if len(S) == 1: return list(S) 4 | v = S.pop() 5 | seq = naive_topsort(G, S) 6 | min_i = 0 7 | for i, u in enumerate(seq): 8 | if v in G[u]: min_i = i+1 9 | seq.insert(min_i, v) 10 | return seq 11 | 12 | def topsort(G): 13 | count = dict((u, 0) for u in G) 14 | for u in G: 15 | for v in G[u]: 16 | count[v] += 1 17 | Q = [u for u in G if count[u] == 0] 18 | S = [] 19 | while Q: 20 | u = Q.pop() 21 | S.append(u) 22 | for v in G[u]: 23 | count[v] -= 1 24 | if count[v] == 0: 25 | Q.append(v) 26 | return S 27 | -------------------------------------------------------------------------------- /fibo.py: -------------------------------------------------------------------------------- 1 | # 2 | def fibo1(n): 3 | if n == 0: return 0 4 | elif n == 1: return 1 5 | else: return fibo1(n-1)+fibo1(n-2) 6 | 7 | def fibo2(n): 8 | return ((1+sqrt(5))**n-(1-sqrt(5))**n)/(2**n*sqrt(5)) 9 | 10 | def fibo3(n): 11 | a,b = 0,1 12 | yield a 13 | yield b 14 | while True: 15 | a,b = b,a+b 16 | yield b 17 | 18 | def subfibo1(start, end): 19 | n = 0 20 | cur = fibo2(n) 21 | while cur<=end: 22 | if start<= cur: 23 | print cur 24 | n += 1 25 | cur = fibo2(n) 26 | 27 | def subfibo2(start, end): 28 | for cur in fibo2(): 29 | if cur>end: return 30 | if cur>=start: 31 | yield cur 32 | 33 | for i in subfibo1(10, 200): 34 | print i 35 | -------------------------------------------------------------------------------- /bmh.py: -------------------------------------------------------------------------------- 1 | # bmh.py 2 | # 3 | # An implementation of Boyer-Moore-Horspool string searching. 4 | def boyermoorehorspool(pattern, text): 5 | m = len(pattern) 6 | n = len(text) 7 | if m > n: return -1 8 | skip = [] 9 | for k in range(256): skip.append(m) 10 | for k in range(m - 1): skip[ord(pattern[k])] = m - k - 1 11 | skip = tuple(skip) 12 | k = m - 1 13 | while k < n: 14 | j = m - 1; i = k 15 | while j >= 0 and text[i] == pattern[j]: 16 | j -= 1; i -= 1 17 | if j == -1: return i + 1 18 | k += skip[ord(text[k])] 19 | return -1 20 | 21 | if __name__ == '__main__': 22 | text = "this is the string to search in" 23 | pattern = "the" 24 | s = BoyerMooreHorspool(pattern, text) 25 | print 'Text:',text 26 | print 'Pattern:',pattern 27 | if s > -1: 28 | print 'Pattern \"' + pattern + '\" found at position',s 29 | -------------------------------------------------------------------------------- /celebrityproblem.py: -------------------------------------------------------------------------------- 1 | def naive_celeb(G): 2 | n = len(G) 3 | for u in range(n): 4 | for v in range(n): 5 | if u == v: continue 6 | if G[u][v]: break 7 | if not G[v][u]: break 8 | else: 9 | return u 10 | return None 11 | 12 | def celeb(G): 13 | n = len(G) 14 | u, v = 0, 1 15 | for c in range(2,n+1): 16 | if G[u][v]: 17 | u = c 18 | else: 19 | v = c 20 | if u == n: 21 | c = v 22 | else: 23 | c = u 24 | 25 | for v in range(n): 26 | if c == v: 27 | continue 28 | if G[c][v]: 29 | break 30 | if not G[v][c]: 31 | break 32 | else: 33 | return c 34 | return None 35 | 36 | from random import randrange 37 | n = 100 38 | G = [[randrange(2) for i in range(n)] for i in range(n)] 39 | 40 | c = randrange(n) 41 | for i in range(n): 42 | G[i][c] = True 43 | G[c][i] = False 44 | naive_celeb(G) 45 | celeb(G) 46 | -------------------------------------------------------------------------------- /quicksort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | def partition(list, start, end): 4 | pivot = list[end] 5 | bottom = start-1 6 | top = end 7 | done = 0 8 | while not done: 9 | while not done: 10 | bottom = bottom+1 11 | if bottom == top: 12 | done = 1 13 | break 14 | if list[bottom] > pivot: 15 | list[top] = list[bottom] 16 | break 17 | 18 | while not done: 19 | top = top-1 20 | if top == bottom: 21 | done = 1 22 | break 23 | if list[top] < pivot: 24 | list[bottom] = list[top] 25 | break 26 | 27 | list[top] = pivot 28 | return top 29 | 30 | 31 | def quicksort(list, start, end): 32 | if start < end: 33 | split = partition(list, start, end) 34 | quicksort(list, start, split-1) 35 | quicksort(list, split+1, end) 36 | else: 37 | return 38 | 39 | 40 | if __name__== "__main__": 41 | import sys 42 | list = map(int,sys.argv[1:]) 43 | start = 0 44 | end = len(list)-1 45 | quicksort(list,start,end) 46 | import string 47 | print string.join(map(str,list)) 48 | -------------------------------------------------------------------------------- /mergesort.py: -------------------------------------------------------------------------------- 1 | #Merges two sorted lists into one sorted list. recursively 2 | def merge(left, right): 3 | if len(left) == 0 and len(right) == 0: 4 | return [] 5 | elif len(left) == 0: 6 | return right 7 | elif len(right) == 0: 8 | return left 9 | else: 10 | if left[0] <= right[0]: 11 | return left[:1] + merge(left[1:],right) 12 | else: 13 | return right[:1] + merge(left,right[1:]) 14 | 15 | #Splits a list in half and returns the halves 16 | def halve(list): 17 | return list[:len(list)//2],list[len(list)//2:] 18 | 19 | #Mergesort 20 | def mergesort(list): 21 | if len(list) <= 1: 22 | return list 23 | left,right = halve(list) 24 | left,right = mergesort(left),mergesort(right) 25 | return merge(left,right) 26 | 27 | 28 | def mergesort2(seq): 29 | mid = len(seq) // 2 30 | lft, rgt = seq[:mid], seq[mid:] 31 | if len(lft) > 1: 32 | lft = mergesort(lft) 33 | if len(rgt) > 1: 34 | rgt = mergesort(rgt) 35 | 36 | res = [] 37 | while lft and rgt: 38 | if lgt[-1] >= rgt[-1]: 39 | res.append(lft.pop()) 40 | else: 41 | res.append(rgt.pop()) 42 | res.reverse() 43 | return (lft or rgt) + res 44 | 45 | -------------------------------------------------------------------------------- /kmp.py: -------------------------------------------------------------------------------- 1 | def KnuthMorrisPratt(text, pattern): 2 | """ 3 | Yields all starting positions of copies of the pattern in the text. 4 | Calling conventions are similar to string.find, but its arguments can be 5 | lists or iterators, not just strings, it returns all matches, not just 6 | the first one, and it does not need the whole text in memory at once. 7 | Whenever it yields, it will have read the text exactly up to and including 8 | the match that caused the yield. 9 | """ 10 | 11 | # allow indexing into pattern and protect against change during yield 12 | pattern = list(pattern) 13 | 14 | # build table of shift amounts 15 | shifts = [1] * (len(pattern) + 1) 16 | shift = 1 17 | for pos in range(len(pattern)): 18 | while shift <= pos and pattern[pos] != pattern[pos-shift]: 19 | shift += shifts[pos-shift] 20 | shifts[pos+1] = shift 21 | 22 | # do the actual search 23 | startPos = 0 24 | matchLen = 0 25 | for c in text: 26 | while matchLen == len(pattern) or \ 27 | matchLen >= 0 and pattern[matchLen] != c: 28 | startPos += shifts[matchLen] 29 | matchLen -= shifts[matchLen] 30 | matchLen += 1 31 | if matchLen == len(pattern): 32 | yield startPos 33 | -------------------------------------------------------------------------------- /josephus.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Josephus permutation. A theoretical problem related to a certain 5 | counting out game. See en.wikipedia.org/wiki/Josephus_problem 6 | or http://mathworld.wolfram.com/JosephusProblem.html for more details. 7 | 8 | Created by Huascar A. Sanchez on 2011-03-21. 9 | Copyright (c) 2011 Huascar A. Sanchez. All rights reserved. 10 | """ 11 | 12 | from collections import deque 13 | def Josephus(m,n,s = 1): 14 | """Josephus problem. Only s survivor (s) (the winner(s)). 15 | Input: n - number of people in the circle 16 | m - frequency of people to be killed. 17 | s - number of survivors you want. 18 | Output: not output. all results will be printed 19 | on screen. 20 | """ 21 | N = n + 1 22 | M = m - 1 23 | S = s 24 | if S <= 0: S = 1 # only one survivor 25 | Q = deque() 26 | #print("construct the list\n") 27 | for p in range(1,N): 28 | Q.append(p) 29 | 30 | toString = [] 31 | #print("start the game now!!\n") 32 | while len(Q) > S: 33 | for dp in range(0,M): 34 | Q.append(Q.popleft()) 35 | toString.append(str(Q.popleft())) 36 | 37 | print(' '.join(toString)) 38 | while Q: 39 | print("winner " + str(Q.popleft())) 40 | 41 | Josephus(5,9) 42 | Josephus(3,40,2) 43 | -------------------------------------------------------------------------------- /sieve1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | def sieve1(n): 5 | a = [0] * n # создание массива с n количеством элементов 6 | for i in range(n): # заполнение массива ... 7 | a[i] = i # значениями от 0 до n-1 8 | 9 | # вторым элементом является единица, которую не считают простым числом 10 | # забиваем ее нулем. 11 | a[1] = 0 12 | 13 | m = 2 # замена на 0 начинается с 3-го элемента (первые два уже нули) 14 | while m < n: # перебор всех элементов до заданного числа 15 | if a[m] != 0: # если он не равен нулю, то 16 | j = m * 2 # увеличить в два раза (текущий элемент простое число) 17 | while j < n: 18 | a[j] = 0 # заменить на 0 19 | j = j + m # перейти в позицию на m больше 20 | m += 1 21 | 22 | # вывод простых чисел на экран (может быть реализован как угодно) 23 | b = [] 24 | for i in a: 25 | if a[i] != 0: 26 | b.append(a[i]) 27 | 28 | del a 29 | print (b) 30 | 31 | def sieve2(n): 32 | primes = [i for i in range(1, n+1)] 33 | primes[0] = 0 34 | 35 | for i in xrange(0, n): 36 | if primes[i] != 0: 37 | for j in xrange(i+primes[i], n, primes[i]): 38 | primes[j] = 0 39 | 40 | lst = [x for x in primes if x != 0] 41 | print lst 42 | 43 | 44 | if __name__ == '__main__': 45 | sieve1(50) 46 | sieve2(50) 47 | -------------------------------------------------------------------------------- /trees.py: -------------------------------------------------------------------------------- 1 | class Tree: 2 | """ 3 | Binary tree. 4 | 5 | >>> t = Tree(Tree("a", "b"), Tree("c", "d")) 6 | >>> t.right.left 7 | 'c' 8 | """ 9 | 10 | [1, 1, 2, 6, 24, 120] 11 | def __init__(self, left, right): 12 | self.left = left 13 | self.right = right 14 | 15 | class Tree: 16 | """ 17 | Multiway tree class. 18 | 19 | >>> t = Tree(Tree("a", Tree("b", Tree("c", Tree("d"))))) 20 | >>> t.kids.next.next.val 21 | 'c' 22 | """ 23 | def __init__(self, kids, next=None): 24 | self.kids = self.val = kids 25 | self.next = next 26 | 27 | class Bunch(dict): 28 | """ 29 | The Bunch pattern. 30 | 31 | >>> x = Bunch(name="Jayne Cobb", position="Public Relations") 32 | >>> x.name 33 | 'Jayne Cobb' 34 | Second, by subclassing dict, you get lots of functionality for free, such as iterating over the keys/attributes 35 | or easily checking whether an attribute is present. Here’s an example: 36 | >>> T = Bunch 37 | >>> t = T(left=T(left="a", right="b"), right=T(left="c")) 38 | >>> t.left 39 | {'right': 'b', 'left': 'a'} 40 | >>> t.left.right 41 | 'b' 42 | >>> t['left']['right'] 43 | 'b' 44 | >>> "left" in t.right 45 | True 46 | >>> "right" in t.right 47 | False 48 | """ 49 | def __init__(self, *args, **kwds): 50 | super(Bunch, self).__init__(*args, **kwds) 51 | self.__dict__ = self 52 | 53 | 54 | if __name__ == "__main__": 55 | import doctest 56 | doctest.testmod() 57 | -------------------------------------------------------------------------------- /graphs.py: -------------------------------------------------------------------------------- 1 | # Adjacency lists 2 | a, b, c, d, e, f, g, h = range(8) 3 | N = [ 4 | [b, c, d, e, f], # a 5 | [c, e], # b 6 | [d], # c 7 | [e], # d 8 | [f], # e 9 | [c, g, h], # f 10 | [f, h], # g 11 | [f, g] # h 12 | ] 13 | 14 | # Adjacency dicts with Edge Weights 15 | a, b, c, d, e, f, g, h = range(8) 16 | N = [ 17 | {b:2, c:1, d:3, e:9, f:4}, # a 18 | {c:4, e:3}, # b 19 | {d:8}, # c 20 | {e:7}, # d 21 | {f:5}, # e 22 | {c:2, g:2, h:2}, # f 23 | {f:1, h:6}, # g 24 | {f:9, g:8} # h 25 | ] 26 | 27 | # A Dict with Adjacency Sets 28 | N = { 29 | 'a': set('bcdef'), 30 | 'b': set('ce'), 31 | 'c': set('d'), 32 | 'd': set('e'), 33 | 'e': set('f'), 34 | 'f': set('cgh'), 35 | 'g': set('fh'), 36 | 'h': set('fg') 37 | } 38 | 39 | # An Adjacency Matrix, Implemented with Nested Lists 40 | a, b, c, d, e, f, g, h = range(8) 41 | N = [[0,1,1,1,1,1,0,0], 42 | [0,0,1,0,1,0,0,0], 43 | [0,0,0,1,0,0,0,0], 44 | [0,0,0,0,1,0,0,0], 45 | [0,0,0,0,0,1,0,0], 46 | [0,0,1,0,0,0,1,1], 47 | [0,0,0,0,0,1,0,1], 48 | [0,0,0,0,0,1,1,0]] 49 | 50 | # A Weight Matrix with Infinite Weight for Missing Edges 51 | a, b, c, d, e, f, g, h = range(8) 52 | _ = float('inf') 53 | W = [[0,2,1,3,9,4,_,_], 54 | [_,0,4,_,3,_,_,_], 55 | [_,_,0,8,_,_,_,_], 56 | [_,_,_,0,7,_,_,_], 57 | [_,_,_,_,0,5,_,_], 58 | [_,_,2,_,_,0,2,2], 59 | [_,_,_,_,_,1,0,6], 60 | [_,_,_,_,_,9,8,0]] 61 | 62 | def recursive_dfs(graph, start, path=[]): 63 | """Recursive depth first search from start.""" 64 | path=path+[start] 65 | for node in graph[start]: 66 | if not node in path: 67 | path=recursive_dfs(graph, node, path) 68 | return path 69 | 70 | def iterative_dfs(graph, start, path=[]): 71 | """Iterative depth first search from start.""" 72 | q=[start] 73 | while q: 74 | v=q.pop(0) 75 | if v not in path: 76 | path=path+[v] 77 | q=graph[v]+q 78 | return path 79 | 80 | def iterative_bfs(graph, start, path=[]): 81 | """Iterative breadth first search from start.""" 82 | q=[start] 83 | while q: 84 | v=q.pop(0) 85 | if not v in path: 86 | path=path+[v] 87 | q=q+graph[v] 88 | return path 89 | 90 | """ 91 | +---- A 92 | | / \ 93 | | B--D--C 94 | | \ | / 95 | +---- E 96 | """ 97 | 98 | graph = {'A':['B','C'],'B':['D','E'],'C':['D','E'],'D':['E'],'E':['A']} 99 | print 'recursive dfs ', recursive_dfs(graph, 'A') 100 | print 'iterative dfs ', iterative_dfs(graph, 'A') 101 | print 'iterative bfs ', iterative_bfs(graph, 'A') 102 | -------------------------------------------------------------------------------- /factorial.py: -------------------------------------------------------------------------------- 1 | #Newbie programmer 2 | def fact1(x): 3 | if x == 0: 4 | return 1 5 | else: 6 | return x * factorial(x - 1) 7 | print fact1(6) 8 | 9 | #First year programmer, studied Pascal 10 | def fact2(x): 11 | result = 1 12 | i = 2 13 | while i <= x: 14 | result = result * i 15 | i = i + 1 16 | return result 17 | print fact2(6) 18 | 19 | #First year programmer, studied C 20 | def fact3(x): #{ 21 | result = i = 1; 22 | while (i <= x): #{ 23 | result *= i; 24 | i += 1; 25 | #} 26 | return result; 27 | #} 28 | print(fact3(6)) 29 | 30 | #First year programmer, SICP 31 | @tailcall 32 | def fact4(x, acc=1): 33 | if (x > 1): return (fact((x - 1), (acc * x))) 34 | else: return acc 35 | print(fact4(6)) 36 | 37 | #First year programmer, Python 38 | def fact5(x): 39 | res = 1 40 | for i in xrange(2, x + 1): 41 | res *= i 42 | return res 43 | print fact5(6) 44 | 45 | #Lazy Python programmer 46 | def fact6(x): 47 | return x > 1 and x * fact(x - 1) or 1 48 | print fact6(6) 49 | 50 | #Lazier Python programmer 51 | f = lambda x: x and x * f(x - 1) or 1 52 | print f(6) 53 | 54 | #Python expert programmer 55 | import operator as op 56 | import functional as f 57 | fact7 = lambda x: f.foldl(op.mul, 1, xrange(2, x + 1)) 58 | print fact7(6) 59 | 60 | #Python hacker 61 | import sys 62 | @tailcall 63 | def fact8(x, acc=1): 64 | if x: return fact(x.__sub__(1), acc.__mul__(x)) 65 | return acc 66 | sys.stdout.write(str(fact8(6)) + '\n') 67 | 68 | #EXPERT PROGRAMMER 69 | import c_math 70 | fact9 = c_math.fact 71 | print fact(6) 72 | 73 | #ENGLISH EXPERT PROGRAMMER 74 | import c_maths 75 | fact10 = c_maths.fact 76 | print fact(6) 77 | 78 | #Unix programmer 79 | import os 80 | def fact11(x): 81 | os.system('factorial ' + str(x)) 82 | fact(6) 83 | 84 | #Windows programmer 85 | NULL = None 86 | def CalculateAndPrintFactorialEx(dwNumber, 87 | hOutputDevice, 88 | lpLparam, 89 | lpWparam, 90 | lpsscSecurity, 91 | *dwReserved): 92 | if lpsscSecurity != NULL: 93 | return NULL #Not implemented 94 | dwResult = dwCounter = 1 95 | while dwCounter <= dwNumber: 96 | dwResult *= dwCounter 97 | dwCounter += 1 98 | hOutputDevice.write(str(dwResult)) 99 | hOutputDevice.write('\n') 100 | return 1 101 | import sys 102 | CalculateAndPrintFactorialEx(6, sys.stdout, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) 103 | 104 | #Enterprise programmer 105 | def new(cls, *args, **kwargs): 106 | return cls(*args, **kwargs) 107 | 108 | class Number(object): 109 | pass 110 | 111 | class IntegralNumber(int, Number): 112 | def toInt(self): 113 | return new (int, self) 114 | 115 | class InternalBase(object): 116 | def __init__(self, base): 117 | self.base = base.toInt() 118 | 119 | def getBase(self): 120 | return new (IntegralNumber, self.base) 121 | 122 | class MathematicsSystem(object): 123 | def __init__(self, ibase): 124 | Abstract 125 | 126 | @classmethod 127 | def getInstance(cls, ibase): 128 | try: 129 | cls.__instance 130 | except AttributeError: 131 | cls.__instance = new (cls, ibase) 132 | return cls.__instance 133 | 134 | class StandardMathematicsSystem(MathematicsSystem): 135 | def __init__(self, ibase): 136 | if ibase.getBase() != new (IntegralNumber, 2): 137 | raise NotImplementedError 138 | self.base = ibase.getBase() 139 | 140 | def calculateFactorial(self, target): 141 | result = new (IntegralNumber, 1) 142 | i = new (IntegralNumber, 2) 143 | while i <= target: 144 | result = result * i 145 | i = i + new (IntegralNumber, 1) 146 | return result 147 | 148 | print StandardMathematicsSystem.getInstance(new (InternalBase, new (IntegralNumber, 2))).calculateFactorial(new (IntegralNumber, 6)) 149 | -------------------------------------------------------------------------------- /knapsack2.py: -------------------------------------------------------------------------------- 1 | # 0-1 knapsack problem dynamic program 2 | # David Eppstein, ICS, UCI, 2/22/2002 3 | 4 | # each item to be packed is represented as a set of triples (size,value,name) 5 | def itemSize(item): return item[0] 6 | def itemValue(item): return item[1] 7 | def itemName(item): return item[2] 8 | 9 | # example used in lecture 10 | exampleItems = [(3,3,'A'), 11 | (4,1,'B'), 12 | (8,3,'C'), 13 | (10,4,'D'), 14 | (15,3,'E'), 15 | (20,6,'F')] 16 | 17 | exampleSizeLimit = 32 18 | 19 | # inefficient recursive algorithm 20 | # returns optimal value for given 21 | # 22 | # note items[-1] is the last item, items[:-1] is all but the last item 23 | # 24 | def pack1(items,sizeLimit): 25 | if len(items) == 0: 26 | return 0 27 | elif itemSize(items[-1]) > sizeLimit: 28 | return pack(items[:-1],sizeLimit) 29 | else: 30 | return max(pack(items[:-1],sizeLimit), 31 | pack(items[:-1],sizeLimit-itemSize(items[-1])) + 32 | itemValue(items[-1])) 33 | 34 | # refactor so all params are integers 35 | # 36 | def pack2(items,sizeLimit): 37 | def recurse(nItems,lim): 38 | if nItems == 0: 39 | return 0 40 | elif itemSize(items[nItems-1]) > lim: 41 | return recurse(nItems-1,lim) 42 | else: 43 | return max(recurse(nItems-1,lim), 44 | recurse(nItems-1,lim-itemSize(items[nItems-1])) + 45 | itemValue(items[nItems-1])) 46 | return recurse(len(items),sizeLimit) 47 | 48 | # memoize 49 | # 50 | # Unlike previous class examples, I'm going to use a Python dictionary 51 | # rather than a list of lists, because it's similarly efficient but can 52 | # handle double indexing better. Also that way I can use the has_key method 53 | # instead of having to initialize each entry with a flag value. 54 | # 55 | # The difference in actual syntax is dictionary[item1,item2] instead of 56 | # listoflists[item1][item2], and an empty dictionary is {} instead of []. 57 | # The extra pair of parens in has_key is also important. 58 | # 59 | def pack3(items,sizeLimit): 60 | P = {} 61 | 62 | def recurse(nItems,lim): 63 | if not P.has_key((nItems,lim)): 64 | if nItems == 0: 65 | P[nItems,lim] = 0 66 | elif itemSize(items[nItems-1]) > lim: 67 | P[nItems,lim] = recurse(nItems-1,lim) 68 | else: 69 | P[nItems,lim] = max(recurse(nItems-1,lim), 70 | recurse(nItems-1,lim-itemSize(items[nItems-1])) + 71 | itemValue(items[nItems-1])) 72 | return P[nItems,lim] 73 | 74 | return recurse(len(items),sizeLimit) 75 | 76 | # iterate 77 | # 78 | # At this step we have to think about how to order the nested loops over 79 | # the two indices nItems and lim. Each recursive call involves nItems-1, 80 | # so the natural choice is to make the outer loop be over values of nItems. 81 | # The ordering in the inner loop is not so important. 82 | # 83 | # The recursive function definition and has_key lines have been replaced 84 | # by a nested pair of loops. All recursive calls have been replaced 85 | # by dictionary lookups. 86 | # 87 | def pack4(items,sizeLimit): 88 | P = {} 89 | for nItems in range(len(items)+1): 90 | for lim in range(sizeLimit+1): 91 | if nItems == 0: 92 | P[nItems,lim] = 0 93 | elif itemSize(items[nItems-1]) > lim: 94 | P[nItems,lim] = P[nItems-1,lim] 95 | else: 96 | P[nItems,lim] = max(P[nItems-1,lim], 97 | P[nItems-1,lim-itemSize(items[nItems-1])] + 98 | itemValue(items[nItems-1])) 99 | return P[len(items),sizeLimit] 100 | 101 | # backtrack through the matrix of solution values to find actual solution 102 | # 103 | # Like the LCS problem, and unlike the matrix chain problem, we only need 104 | # to backtrack along a single path in the matrix, so we can do it with a 105 | # while loop instead of a recursion. We add each item to the end of a 106 | # list L, then reverse L to match the input order -- it would work to add 107 | # each item to the beginning of L but that's much less efficient in Python. 108 | # 109 | def pack5(items,sizeLimit): 110 | P = {} 111 | for nItems in range(len(items)+1): 112 | for lim in range(sizeLimit+1): 113 | if nItems == 0: 114 | P[nItems,lim] = 0 115 | elif itemSize(items[nItems-1]) > lim: 116 | P[nItems,lim] = P[nItems-1,lim] 117 | else: 118 | P[nItems,lim] = max(P[nItems-1,lim], 119 | P[nItems-1,lim-itemSize(items[nItems-1])] + 120 | itemValue(items[nItems-1])) 121 | 122 | L = [] 123 | nItems = len(items) 124 | lim = sizeLimit 125 | while nItems > 0: 126 | if P[nItems,lim] == P[nItems-1,lim]: 127 | nItems -= 1 128 | else: 129 | nItems -= 1 130 | L.append(itemName(items[nItems])) 131 | lim -= itemSize(items[nItems]) 132 | 133 | L.reverse() 134 | return L 135 | 136 | # run the example 137 | # output = ['A', 'C', 'F'] 138 | print pack5(exampleItems,exampleSizeLimit) 139 | -------------------------------------------------------------------------------- /knapsack.py: -------------------------------------------------------------------------------- 1 | # Simple Brute-Force Solution 2 | class Bounty: 3 | def __init__(self, value, weight, volume): 4 | self.value, self.weight, self.volume = value, weight, volume 5 | 6 | panacea = Bounty(3000, 0.3, 0.025) 7 | ichor = Bounty(1800, 0.2, 0.015) 8 | gold = Bounty(2500, 2.0, 0.002) 9 | sack = Bounty( 0, 25.0, 0.25) 10 | best = Bounty( 0, 0, 0) 11 | current = Bounty( 0, 0, 0) 12 | 13 | best_amounts = (0, 0, 0) 14 | 15 | max_panacea = int(min(sack.weight // panacea.weight, sack.volume // panacea.volume)) 16 | max_ichor = int(min(sack.weight // ichor.weight, sack.volume // ichor.volume)) 17 | max_gold = int(min(sack.weight // gold.weight, sack.volume // gold.volume)) 18 | 19 | for npanacea in xrange(max_panacea): 20 | for nichor in xrange(max_ichor): 21 | for ngold in xrange(max_gold): 22 | current.value = npanacea * panacea.value + nichor * ichor.value + ngold * gold.value 23 | current.weight = npanacea * panacea.weight + nichor * ichor.weight + ngold * gold.weight 24 | current.volume = npanacea * panacea.volume + nichor * ichor.volume + ngold * gold.volume 25 | 26 | if current.value > best.value and current.weight <= sack.weight and \ 27 | current.volume <= sack.volume: 28 | best = Bounty(current.value, current.weight, current.volume) 29 | best_amounts = (npanacea, nichor, ngold) 30 | 31 | print "Maximum value achievable is", best.value 32 | print "This is achieved by carrying (one solution) %d panacea, %d ichor and %d gold" % \ 33 | (best_amounts[0], best_amounts[1], best_amounts[2]) 34 | print "The weight to carry is %4.1f and the volume used is %5.3f" % (best.weight, best.volume) 35 | 36 | # General Brute-Force Solution 37 | # Requires Python V.2.6+ 38 | 39 | 40 | from itertools import product, izip 41 | from collections import namedtuple 42 | Bounty = namedtuple('Bounty', 'name value weight volume') 43 | sack = Bounty('sack', 0, 25.0, 0.25) 44 | items = [Bounty('panacea', 3000, 0.3, 0.025), 45 | Bounty('ichor', 1800, 0.2, 0.015), 46 | Bounty('gold', 2500, 2.0, 0.002)] 47 | 48 | def tot_value(items_count): 49 | """ 50 | Given the count of each item in the sack return -1 if they can't be carried or their total value. 51 | 52 | (also return the negative of the weight and the volume so taking the max of a series of return 53 | values will minimise the weight if values tie, and minimise the volume if values and weights tie). 54 | """ 55 | global items, sack 56 | weight = sum(n * item.weight for n, item in izip(items_count, items)) 57 | volume = sum(n * item.volume for n, item in izip(items_count, items)) 58 | if weight <= sack.weight and volume <= sack.volume: 59 | return sum(n * item.value for n, item in izip(items_count, items)), -weight, -volume 60 | else: 61 | return -1, 0, 0 62 | 63 | 64 | def knapsack(): 65 | global items, sack 66 | # find max of any one item 67 | max1 = [min(int(sack.weight // item.weight), int(sack.volume // item.volume)) for item in items] 68 | 69 | # Try all combinations of bounty items from 0 up to max1 70 | return max(product(*[xrange(n + 1) for n in max1]), key=tot_value) 71 | 72 | max_items = knapsack() 73 | maxvalue, max_weight, max_volume = tot_value(max_items) 74 | max_weight = -max_weight 75 | max_volume = -max_volume 76 | 77 | print "The maximum value achievable (by exhaustive search) is %g." % maxvalue 78 | item_names = ", ".join(item.name for item in items) 79 | print " The number of %s items to achieve this is: %s, respectively." % (item_names, max_items) 80 | print " The weight to carry is %.3g, and the volume used is %.3g." % (max_weight, max_volume) 81 | 82 | 83 | """ 84 | Specific Dynamic Programming solution 85 | 86 | A dynamic programming approach using a 2-dimensional table (One dimension for 87 | weight and one for volume). Because this approach requires that all weights and 88 | volumes be integer, I multiplied the weights and volumes by enough to make them 89 | integer. This algorithm takes O(w*v) space and O(w*v*n) time, where w = weight 90 | of sack, v = volume of sack, n = number of types of items. To solve this 91 | specific problem it's much slower than the brute force solution. 92 | """ 93 | 94 | from itertools import product, izip 95 | from collections import namedtuple 96 | 97 | Bounty = namedtuple('Bounty', 'name value weight volume') 98 | 99 | # "namedtuple" is only available in Python 2.6+; for earlier versions use this instead: 100 | # class Bounty: 101 | # def __init__(self, name, value, weight, volume): 102 | # self.name = name 103 | # self.value = value 104 | # self.weight = weight 105 | # self.volume = volume 106 | 107 | sack = Bounty('sack', 0, 250, 250) 108 | 109 | items = [Bounty('panacea', 3000, 3, 25), 110 | Bounty('ichor', 1800, 2, 15), 111 | Bounty('gold', 2500, 20, 2)] 112 | 113 | 114 | def tot_value(items_count, items, sack): 115 | """ 116 | Given the count of each item in the sack return -1 if they can't be carried or their total value. 117 | 118 | (also return the negative of the weight and the volume so taking the max of a series of return 119 | values will minimise the weight if values tie, and minimise the volume if values and weights tie). 120 | """ 121 | weight = sum(n * item.weight for n, item in izip(items_count, items)) 122 | volume = sum(n * item.volume for n, item in izip(items_count, items)) 123 | if weight <= sack.weight and volume <= sack.volume: 124 | return sum(n * item.value for n, item in izip(items_count, items)), -weight, -volume 125 | else: 126 | return -1, 0, 0 127 | 128 | def knapsack_dp(items, sack): 129 | """ 130 | Solves the Knapsack problem, with two sets of weights, 131 | using a dynamic programming approach 132 | """ 133 | # (weight+1) x (volume+1) table 134 | # table[w][v] is the maximum value that can be achieved 135 | # with a sack of weight w and volume v. 136 | # They all start out as 0 (empty sack) 137 | table = [[0] * (sack.volume + 1) for i in xrange(sack.weight + 1)] 138 | 139 | for w in xrange(sack.weight + 1): 140 | for v in xrange(sack.volume + 1): 141 | # Consider the optimal solution, and consider the "last item" added 142 | # to the sack. Removing this item must produce an optimal solution 143 | # to the subproblem with the sack's weight and volume reduced by that 144 | # of the item. So we search through all possible "last items": 145 | for item in items: 146 | # Only consider items that would fit: 147 | if w >= item.weight and v >= item.volume: 148 | table[w][v] = max(table[w][v], 149 | # Optimal solution to subproblem + value of item: 150 | table[w - item.weight][v - item.volume] + item.value) 151 | 152 | # Backtrack through matrix to re-construct optimum: 153 | result = [0] * len(items) 154 | w = sack.weight 155 | v = sack.volume 156 | while table[w][v]: 157 | # Find the last item that was added: 158 | aux = [table[w-item.weight][v-item.volume] + item.value for item in items] 159 | i = aux.index(table[w][v]) 160 | 161 | # Record it in the result, and remove it: 162 | result[i] += 1 163 | w -= items[i].weight 164 | v -= items[i].volume 165 | 166 | return result 167 | 168 | 169 | max_items = knapsack_dp(items, sack) 170 | max_value, max_weight, max_volume = tot_value(max_items, items, sack) 171 | max_weight = -max_weight 172 | max_volume = -max_volume 173 | 174 | print "The maximum value achievable (by exhaustive search) is %g." % max_value 175 | item_names = ", ".join(item.name for item in items) 176 | print " The number of %s items to achieve this is: %s, respectively." % (item_names, max_items) 177 | print " The weight to carry is %.3g, and the volume used is %.3g." % (max_weight, max_volume) 178 | --------------------------------------------------------------------------------