├── Readme.md ├── chapter0 ├── chapter1 ├── chapter2 ├── chapter3 ├── chapter4 ├── chapter5 ├── chapter6 ├── chapter7 ├── chapter8 ├── chapter9 └── code ├── BellmanFord.py ├── FastFourier.py ├── MaxContiguousSubsequence.py ├── depthFirstSearch.py ├── dijkstra.py ├── iterDFS.py ├── mergesort.py ├── minimumSpanningTree.py ├── multilpyDivideAndConquer.py ├── multiply.py ├── primsAlgo.py ├── priorityQueue.py ├── recursivefunction.py └── stronglyConnectComponent.py /Readme.md: -------------------------------------------------------------------------------- 1 | My attempts to solve Algorithms by S. Dasgupta, C. H. Papadimitriou, and U. V. Vazirani 2 | Please offer your thoughts and corrections. WIP. 3 | I decided to put it online since someone might find it useful and in 4 | the hope I get corrected too. 5 | -------------------------------------------------------------------------------- /chapter0: -------------------------------------------------------------------------------- 1 | f = O(g) means that as n ( the problem size tends to infinity) f is bounded above by g 2 | f = Ω(g) means that as n ( the problem size tends to infinity) f is bounded below by g 3 | f = Θ(g) means that as n ( the problem size tends to infinity) f is bounded both above and below by g 4 | f=O(g) is analogous to f<=g 5 | 0.1 6 | statement check 7 | (a) f=Θ(g) yes 8 | (b) f=O(g) yes 9 | (c) f=Θ(g) yes 10 | (d) f=Θ(g) yes 11 | (e) f=Θ(g) yes 12 | (f) f=Θ(g) yes 13 | (g) f=O(g) #unsure 14 | (h) f=Ω(g) yes 15 | (i) f=Ω(g) #unsure 16 | (j) f=Ω(g) yes 17 | (k) f=Ω(g) yes 18 | (l) f=Θ(g) #unsure 19 | (m) f=Θ(g) #unsure 20 | (n) f=Θ(g) yes 21 | (o) f=Ω(g) yes 22 | (p) f=Ω(g) #unsure 23 | (q) f=O(g) yes 24 | #need to cross check later 25 | 26 | 0.2 27 | (a) if c<1. then it can be expressed as (1-c^(n+1))/(1-c). 28 | at the limit, this is 1/(1-c). I can always get a constant 29 | number greater than this and the lower bound is 1 thus it is Θ(g) 30 | (b) then g(n)=n which is clearly Θ(n) 31 | (c) I could use n*c^n as an upper bound and c^n as a lower bound. 32 | it is bounded from both ends by c^n functions and thus is Θ(c^n) 33 | 34 | 0.3 35 | F6 is what? 36 | F0=0 37 | F1=1 38 | F2=1 39 | F3=2 40 | F4=3 41 | F5=5 42 | F6=8 which is greater than or equal to 2^3 43 | F7=13 which is greater than or equal to 2^3.5 44 | F8=21 which is greater than or equal to 2^4 45 | Assume that Fn-1 >= 2^(0.5*(n-1)) 46 | Assume that Fn-2 >= 2^(0.5*(n-2)) 47 | then I need to prove that Fn>=2^(0.5*n) 48 | expanding the left hand side 49 | Fn=Fn-1+Fn-2 50 | it suffices to prove that 2^(0.5(n-1))+2^(0.5(n-2))>=2^(0.5n) 51 | 2^(0.5(n-2))*(2^0.5+1)>=2^(0.5n) 52 | 2^0.5+1>=2 which is true since 2^0.5==1.414.. 53 | QED! 54 | 55 | 0.4 56 | (a) for a 2x2 matrices 57 | (a b) X (e f) = (ae+bg af+bh) 58 | (c d) (g h) (ce+dg cf+dh) 59 | there are four additions and eight multiplications 60 | (b) basically multiplication by squaring. Recursively, 61 | if you have X^N, this is (X^N/2)^2 if N is even or 62 | X*X^N-1 if N is odd. then apply this recursively. 63 | This alternates between halving and reducing the problem 64 | size by one at each iteration. so it will take 65 | log(N) steps 66 | 67 | (c) Show that all intermediate results of fib3 are O(n) bits long 68 | we start with just one bit.When you multiply two 1 bit numbers 69 | and add two of them, you can get at most 2 bits numbers. 70 | The general argument is that by adding two numbers that have n 71 | bits, you can get at best a n+1 bit number. QED 72 | 73 | (d) At each iteration you do 8 multiplications. Each multiplication 74 | is M(n) and there are logn iterations so O(M(n)logn). QED 75 | 76 | (e) hm.. M(n)/4^(k) for multiplications at each iteration. Add this up and 77 | we have 1-4^(k+1)/(1-1/4) = C and we have C*O(m) multiplications required 78 | QED -------------------------------------------------------------------------------- /chapter1: -------------------------------------------------------------------------------- 1 | 1.1 2 | true because, the maximum possible value for the addition of three single bit numbers is 3*(b-1) 3 | where b is the base. it is at most 2 bit long since 3*(b-1) <=b**3 for all b>=2 4 | 5 | 1.2 6 | the representation of a number in a given base has a length, logn/logb 7 | so for a given n, we have logn/log2 for base 2 as the number of digits 8 | and logn/log(10) for base 10 as the number of digits 9 | so log(10)/log(2) which is 1/0.3010 .. which is 3.something , the ceil of which is 4 10 | 11 | 1.3 12 | depth should be >=logn/logd 13 | The tree has the least possible depth when completely filled at each level 14 | At level 1, we have d children 15 | level 2, we have d^2 children 16 | and at level n we have d^n children 17 | in total, if completely filled, the tree has O(d^(h+1)) nodes..(when you sum the geometric series, you get (d^(h+1)-1)/(d-1) ) 18 | h is the number such that d raised to h is n. which is logn/logd 19 | 20 | 1.4 Show that log(n!) = 0(nlogn) 21 | first show that n!log(n/2). clearly 26 | sum(log i ) for i, 1 to n>n/2log(n/2) 27 | 28 | 1.5 29 | the series is Sum 1/i for i =1 to n to show that the upper bound is logn. increase each number to the next power of two. 30 | This means that each number is going to be 2^p and there are going to be 2^p of each power of two. for n there is at most logn 31 | powers of two and each term add about 1 to the sum. so the answer is O(logn). 32 | For the lower bound, each each number to the next power of 2. For each power,2^-k, there are 2^(k-1) terms so each power present 33 | contributes half to the sum, there are logn powers present in the series so Omega(logn). 34 | Since O(logn ) and Omega(logn) then Theta(logn) as it was required to prove. 35 | 36 | 1.6 37 | It works! 38 | basically if you have for example 1001010*101011. Basically in the binary representation, we represent the number as a sum 39 | of powers of two. what the grade school multiplication is multiply by these powers individually and add the sum. 40 | 41 | 1.7 42 | How long does the recursive multiplication algo take to multiply a n-bit number and m-bit number 43 | at each level, the m-bit number get reduced by one bit and you either multiply by 2 or add n-bit number with m-k bit number 44 | where k is the level. that's O(max(m,n)) at each step. so O(mn) 45 | 46 | 1.8 47 | Suppose you know that k=qy+r 48 | what is x? where x=2k and x=2k=1. 49 | for case 1. 50 | 2k=2qy+2r, x = 2qy+2r , then we need to make sure that 2r (the remainder term) is less than q. if it isnt then we get 2q+1 51 | for our q term. 52 | for case 2. 53 | 2k=2qy+2r+1, x=2qy+2r+1, then we need to make sure that 2r+1( the remainder term is less than q). if it isnt then we get 2q+1 54 | for our q term. 55 | 56 | 1.9 57 | if x-x` is divisible by N and y-y` is divisible by N. then x+y-x`-y` is also divisible by N and thus 58 | x+y=x`+y` mod N 59 | 60 | 1.10 61 | a=b mod N means that a+Nk=b 62 | if M divides N i.e N=CM then a +N*C*M=b which is of the form a+Q*M=b 63 | which means that a=b mod M 64 | 65 | 1.11 66 | yes , (4^6) %35 =1 67 | (9^6) %35 =1 68 | 4^1536 is 4^6*256=1 69 | 9^4824 is 9^6*804=1 70 | 1-1=0 71 | so 4^1536-9^4824=0 modulo 35 72 | 73 | 1.12 74 | 2= -1 modulo 3 75 | (-1)^(2^2008) ==1 modulo 3 76 | 77 | 1.13 78 | 5*5=25 which is -6 79 | -6*-6 =36 which is 6 80 | 6*6 =36=6 81 | 5^4=6 82 | 5^4*k=6 so 5^30000 = 6 83 | 6^2=6 84 | 6^(2*k)=6 85 | 6-6=0 modulo 31 so 5^(30000)-6^(123456) is divisible by 31 86 | 87 | 1.14 88 | Use matrices! 89 | Compute my repeated squaring and make sure your result is still modulo p. Each multiplication is at most logp^2 - a constant 90 | steps. the same multiplications but mod p 91 | So we have O(M(n)) and M(n) is a constant logp^2 92 | 93 | 1.15 94 | find necessary and sufficient conditions such that 95 | ax=bx mod c. then a=b 96 | x has to have an inverse mod c so you can multiply both sides by the inverse of x 97 | 98 | 1.16 99 | n^15. 100 | By squaring. we need to calculate the 2,3,6,7,14,15 - that's 6 101 | but it can be done with 2,3,6,12,15 - that's 5 multiplications that generate these numbers 102 | Oh.. it is mod c. so just need the inverse of a. to compute some powers 103 | 104 | 1.17 #Unsure about my arguments 105 | y-1 multiplications for the iterative algo. at each iterative step k, we multiply n-bit number by a kn bit number. 106 | which is O(y*n) (there are up to y steps. similar to 1+2+3..y). and so the entire algorithm takes O(n*y^2) for the entire operation. 107 | for the recursive exponential squaring, we have logy steps. but each multiplication takes O(2^2k) for each iteration k. 108 | That's O(N) for the entire algorithm 109 | 110 | 1.18 111 | gcd(220,588) by factorization and by the euclid algorithm 112 | 220=10*22 = 2*2*5*11 113 | 588=2*298=2*2*149 114 | so gcd is 4 115 | by the euclid algo. 116 | gcd(220,588)=gcd(220,588-220)=gcd(220,368)=gcd(220,148)=gcd(220-148,148)=gcd(72,148)=gcd(72,148-72)=gcd(72,76)=gcd(72,4)=gcd(0,4)=4 117 | 118 | 1.19 119 | gcd(Fn+1,Fn) = gcd(Fn-1,Fn) = until you get to gcd(1,2)=1 at the base case 120 | 121 | 1.20 122 | inverse of 20 mod 79 is 4 123 | inverse of 3 mod 62 is 33 124 | inverse of 21 mod 91 is no inverse, gcd is not zero 125 | inverse of 5 mod 23 is 14 126 | 127 | 1.21 128 | every number except multiples of 11 129 | 130 | 1.22 131 | True. if it has an inverse we can find ax+by=1 which means ax=1 mod b or by=1 mod a. they both have mod inverse mod each other 132 | 133 | 1.25 134 | 2^125 mod 127. 127 is prime, which means that 2^126=1. what's the mod inverse of 2 mod 127? 64? yes. so 2^125=64 mod 127 135 | 136 | 1.26 find the least significant digit of 17^(17^17) 137 | it is 7. 138 | using a^(p-1)(q-1) =1 mod(pq) 139 | in this case pq is 2 and 5. 140 | so 17^4=1 141 | so we need to find what 17^17 is mod 4. it is clearly 1 since. 17=4*4=1 142 | so we have 17^1%10 and that's 7 143 | 144 | 1.27 145 | what's the inverse of e=3 mod (p-1)(q-1) 146 | p=17 ;q=23 - 16*22=352. find the mod inverse of 3 mod 352 . it is 235. 147 | So M =41 would be encoded as 41^3 modpq = 105 148 | 149 | 1.28 150 | RSA cryto with p=7,q=11. find the appropriate d and e. 151 | a^(p-1)(q-1)=a mod pq. so we need de = 1 mod(p-1)(q-1) = 60 152 | d=5 and e = 12 153 | 154 | 1.29 155 | (a)Random bits. Just 2? to choose two numbers from m? or is it logm (the number of bits in m?) 156 | It is universal since m is prime. m being prime. Means that the probability that the pair 157 | x1,x2 map to the same hash as y1,y2 is 1/m . We have a1(x1-y1)=a2(x2-y2) mod m . a2 has to be 158 | (x2-y2)^-1*a1(x1-y1)=a2 the probability of that is 159 | (b)if two pairs map to the same hash. then a1(x1-y1)=a2(x2-y2) mod m. where m is 2^k . 160 | 161 | (c) 162 | 163 | 1.31 164 | (a) 165 | How many bits are in N^N. we have NlogN bits. O(NlogN) 166 | How many bits are in N/2^(N/2). we have N/2logN/2 bits . this Omega(NlogN) 167 | so N^N has Theta(NlogN) bits 168 | (b)#Unsure about this argument 169 | iteratively. ans=1 170 | for i in 1 to n, ans*=i 171 | at each stage you are multiplying on average N^2 bits by N bits? N times? for O(N^4)? 172 | 173 | 1.32 174 | (a) 175 | Find the binary representation of N. the square root must have half about length of the binary representation in its own 176 | representation. Then check the numbers that have that length in their binary representation. Can do a binary search. 177 | 1000 to 1111. each step does multiplication. which is O(n^2). and there are at most n/2 multiplications. so we have O(n^3) 178 | With a lookup table for logarithms. We can have O(1). 179 | (b) 180 | (c) 181 | How to determine if a number is a power. Trial and error with a lookup table. Try from logN/2 to logN/floor(logN). the closest 182 | integers with logs just less than and greater than the logs we are checking 183 | 184 | 1.33 185 | The LCM can be computed from the lcm = a*b/gcd(a,b). a*b is O(n^2) if a and b are both n-bit integers. gcd(a,b) is O(n^3) 186 | so in total, the algo is O(n^3) since this term dominates 187 | 188 | 1.34 #Seems like I need to read up and master probability 189 | 190 | 1.35 191 | Wilson's theorem 192 | (a) for a number to be its own inverse mod p. a^2=1 mod p. (a-1)(a+1)=0 mod p. a+1 has to 0 mod p or a-1 has to be 0 mod p. 193 | so we have p-1 is it's own inverse and 1 is it's own inverse. 194 | (b) so every other number, it has to be paired with an other distinct number. p-3 numbers are in pairs of number and inverse and 195 | multiplied together we get 1. 1 and p-1 are multiplied together to get -1. 196 | 197 | (c) consider d=gcd(N,(N-1)!) if N is not prime,then N must have two factors both less than N. so N-1! is a multiple of N. 198 | i.e (N-1)!=0 mod N. 199 | (d) It is computationally expensive. Involving O(N^3) operations 200 | 201 | 1.36 202 | (a) suppose p=3 mod4 show that (p+1)/4 is an integer. if p=3 mod 4 then p=4*k+3. we have (4*k+4)/4 which is an integer 203 | (b) a^(p+1)/2 when squared, a^(4k+4)=a mod p. 204 | 205 | 1.37 206 | (a) repeats in cycles of 3 and 5 respectively. If two numbers have the same remainder mod 3 and 5. then the remainder is mod15 207 | (b) i=j mod p means i=j+mp i=j mod q means i=k+nq. hm.. every number in the range pq, can be expressed as a*q+r . so no two 208 | #Not solved yet 209 | (c) find A such that A=a mod p, A=b mod q, A=c mod r . That's A = a(qr)(qr^-1 mod p)+b(pr)(pr^-1 mod q) +c(qr)(qr^-1 mod r) 210 | 211 | 1.38 212 | (a) p=13, 1001 ,r =3 since 77*13 is 1001. for 17. r=8 213 | (b) we know that 10^(p-1)=1 mod p . Assume r is not a divisor of p-1. then we have 10^(r)=1 mod p. and this system has two 214 | inverses. 215 | 216 | 1.39 217 | a^(b^c) modp . we need to know what b^c is mod(p-1). 218 | 219 | 1.40 220 | it follows that 221 | x^2=1 mod N and x!=1 mod N 222 | we have (x-1)*(x+1)=0 mod N. N is composite. It can be expressed as the product of these two numbers 223 | 224 | 1.41 225 | (a) the set is (0,1,2..p-1) 226 | if x^2=a mod p. then (p-x)^2=a mod p too 227 | 228 | 1.42 229 | Well.. you can easily find the inverse of e. It is simply p-e-1 230 | 231 | 1.43 232 | N,e,d can we factor N? Chinese remainder theorem? hm if e is 3, can we get p and q? need 3*d=1 mod(p-1)(q-1). 233 | 234 | 1.44 235 | 236 | 1.45 237 | (a) To confirm if something is authentic 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | -------------------------------------------------------------------------------- /chapter2: -------------------------------------------------------------------------------- 1 | 2.1 2 | Use divide and conquer to multiply 10011011 and 10111010 3 | we break into 1001 1011 and 1011 1010 - 4 | 5 | 2.2 6 | Show that for any positive integer n and base b, there must be a power of b lieing in the range n,bn 7 | n1 is some constant #dunno 37 | (j) T(n)=2T(n−1)+1, this is O(2^n) 38 | (k) T(n)=T(Sqrt(n))+1 . #dunno 39 | 40 | 2.6 41 | (a) at any time before t0, the impulse response is 1/t0 42 | (b) 1/t0*(1-u(t-t0)) 43 | 44 | 2.7 45 | 0, the sum of the nth roots is always zero 46 | 47 | 2.8 48 | (a) w should be the 8th root of unity 49 | () 50 | 51 | 2.9 Practice polynomial mulplication by FFT 52 | (a) Done 53 | (b) Done 54 | 55 | 2.10 56 | (x-3)(x-5)(x-a)(x-b)=2 when x=1 and =1 when x=2 and=4 when x=4 57 | x=1 , -2*-4*(1-a)(1-b)=2 58 | -1*-3*(2-a)(2-b)=1 59 | 1*(-1)(4-a)(4-b)=4 60 | 61 | 2.11 62 | ehn.. I can multiply everything and "prove it" 63 | Use induction? 64 | 65 | 2.12 66 | T(n)=2*T(n/2) 67 | 68 | 2.13 69 | A little ill-defined. Are we just concerned with the shape? 70 | B3 is 1. 71 | B5 is 1 72 | 73 | 2.14 74 | Sort the array in O(nlogn). create a new array and add to new array 75 | if it is the first occurrence 76 | 77 | 2.15 78 | in place.. keep two limits... if current is less than move limit 79 | left by one position.if current is the same swap 80 | 81 | 2.16 82 | start from pos = 1 and keep multiplying by 2. until the value at pos is greater than 83 | x. then a binary search in the bound, pos/2 and pos. 84 | 85 | 2.17 86 | check pos = n/2 . is A[p/2] = p/2 we are done. if A[p/2]>p . then it can't be found 87 | in the left of the array.. since every thing is at greater than p already. 88 | check the left. where A[p/2]

B is a tree edge 3 | B->C is a tree edge 4 | C->F is a tree edge 5 | F->E is a tree edge 6 | F->I is a tree edge 7 | E->B is a back edge 8 | E->A is a back edge 9 | prev = [0, 1, 2, -1, 4, 3, -1, -1, 6] 10 | post = 11, 10, 9, -1, 5, 8, -1, -1, 7] 11 | 12 | D->G is a tree edge 13 | G->H is a tree edge 14 | H->D is a back edge 15 | prev = [0, 1, 2, 12, 4, 3, 13, 14, 6] 16 | post = [11, 10, 9, 17, 5, 8, 16, 15, 7] 17 | 18 | 3.2 19 | (a) 20 | A->B is a tree edge 21 | B->C is a tree edge 22 | C->D is a tree edge 23 | D->B is a back edge 24 | D->H is a tree edge 25 | H->G is a tree edge 26 | G->F is a tree edge 27 | F->E is a tree edge 28 | A->F is a forward edge 29 | B->E is a forward edge 30 | E->G is a backward edge 31 | E->D is a backward edge 32 | prev = [0, 1, 2, 3, 7, 6, 5, 4] 33 | post = [15, 14, 13, 12, 8, 9, 10, 11] 34 | (b) 35 | Do I really want to do this? I think I grasp this point already 36 | 37 | 3.3 38 | (a) Not sure what the dfs based topo algo is .Oh got it, sort in decreasing 39 | order of post values. 40 | B,A,C,E,D,F,H,G... Yay! 41 | prev = [0, 14, 1, 2, 10, 3, 4, 6, -1] 42 | post = [13, 15, 12, 9, 11, 8, 5, 7, -1] 43 | 44 | (b) A and B are the sources, G and H are the sinks 45 | (c) (A/B)->C->(D/E)->F->(G/H) 46 | (d) it has 8 possible topological orderings 47 | 48 | 3.4 49 | (a) C,D,F,J then G,I,H then A then B then E. 50 | (b) source SCCs are B and E. sink is the component formed by C,D,F,J 51 | (c) Done :) 52 | (d) 2 edges.. basically you need to remove the sources and sink 53 | 54 | 3.5 55 | def reverseGraph(G, u): 56 | for v in G[u]: 57 | if u not in RG[v]: # don't think this is linear time, if I have to search 58 | RG[v].append(u) # make the parent the child in the reversed Graph 59 | reverseGraph(G, v) 60 | I can also do this by extracting all the edges, 61 | reversing them and constructing an adjacency representation again. 62 | 63 | 3.6 64 | (a) every edge represents an addition to the 65 | in and out degree 66 | (b) it is obvious? even+ odd*even = even 67 | (c) 68 | 69 | 3.7 70 | (a) do a dfs but mark each node as belonging to v1 or v2 71 | def dfs(G,u,c): 72 | if colour[u]== -1: # not coloured 73 | colour[u] = c 74 | elif colour[u]!=c: 75 | return False # graph is not bipartite 76 | for v in G[u]: 77 | ans&=dfs(G,v, not(color)) 78 | return ans 79 | 80 | (b) if it has a cycle of odd length.. then 0-1-0-1 81 | (c) 3 colours? 82 | 83 | 3.8 84 | 10,7,4 - exactly 2 pints in 7 or 4 container. 10 - 4 put in the 7 pint container. 85 | then fill the 4 pint container from the 6 pints in the 7 container. 86 | 2 pints in the 7 container. 87 | (a) if there is a path that has a distance of exactly 2? 88 | (b) 89 | (c) 90 | 91 | 3.9 92 | visited[u]=True 93 | ans = 0 94 | for v in G[u]: 95 | if not visited[v]: 96 | dfs(G, v) 97 | ans+=len(G[v]) 98 | twodegree[u] = ans 99 | 100 | 3.10 101 | def dfs(G,u): 102 | visited = [False]*n 103 | stack = [u] 104 | clock = 0 105 | prev[u] = clock 106 | clock+=1 107 | while stack: 108 | u = stack.pop(-1) 109 | visited[u] = True 110 | post[u] = clock 111 | clock+=1 112 | for v in G[u]: 113 | if not visited[v]: 114 | stack.append(v) 115 | prev[v]= clock 116 | clock+=1 117 | 118 | 3.11 119 | Check if there is a back edge that goes from v to e. 120 | You can read this off the post array. 121 | 122 | 3.12 123 | post(u)t and count the number of times, the 186 | algo reaches t 187 | def dfs(G,u): 188 | visited[u] = True 189 | if u == t: 190 | return 1 191 | for v in G[u]: 192 | count += dfs(G,v) 193 | return count 194 | 195 | 3.24 196 | use a dfs to try all paths.. once there is no place to visit. 197 | Count the number of vertices in the path 198 | 199 | 3.25 200 | topo sort. work backwards and do min(cost[u]) for its neighbors 201 | 202 | 3.26 203 | 204 | 3.27 205 | 206 | 3.28 207 | 208 | 3.29 209 | 210 | -------------------------------------------------------------------------------- /chapter4: -------------------------------------------------------------------------------- 1 | 4.1 2 | (a) [inf, 0, inf, inf, inf, inf, inf, inf, inf] 3 | [inf, 0, 1, inf, inf, 4, 8, inf, inf] 4 | [inf, 0, 1, 3, inf, 4, 7, 7, inf] 5 | [inf, 0, 1, 3, 4, 4, 7, 5, inf] 6 | [inf, 0, 1, 3, 4, 4, 7, 5, 8] 7 | [inf, 0, 1, 3, 4, 4, 7, 5, 8] 8 | [inf, 0, 1, 3, 4, 4, 6, 5, 6] 9 | [inf, 0, 1, 3, 4, 4, 6, 5, 6] 10 | [inf, 0, 1, 3, 4, 4, 6, 5, 6] 11 | [inf, 0, 1, 3, 4, 4, 6, 5, 6] 12 | (b) A->B->C->D 13 | | | 14 | E F<-G->H 15 | 16 | 4.2 17 | BellmanFord on the graph at each iteration 18 | 0 [0, inf, inf, inf, inf, inf, inf, inf, inf, inf] 19 | 1 [0, 7, 6, inf, inf, 6, 5, inf, 9, inf] 20 | 2 [0, 7, 6, 5, 7, 6, 4, 4, 2, 3] 21 | 3 [0, 7, 6, 5, 7, 6, 4, 3, 2, 2] 22 | 4 [0, 7, 6, 5, 7, 6, 4, 3, 2, 2] 23 | 5 [0, 7, 6, 5, 7, 6, 4, 3, 2, 2] 24 | 6 [0, 7, 6, 5, 7, 6, 4, 3, 2, 2] 25 | 7 [0, 7, 6, 5, 7, 6, 4, 3, 2, 2] 26 | 8 [0, 7, 6, 5, 7, 6, 4, 3, 2, 2] 27 | 9 [0, 7, 6, 5, 7, 6, 4, 3, 2, 2] 28 | 29 | 4.3 Dfs starting from every node. Count the number of edges it has passed 30 | till it reached the original node again, if it does. 31 | 32 | 4.4 Length of the shortest cycle 33 | What happens when the shortest cycle consists of two backedges? 34 | 35 | 4.5 36 | #not tested yet 37 | def bfs(G, u): 38 | visited[u] = True 39 | level[u] = 0 40 | stack = [u] 41 | while stack: 42 | u = stack.pop(0) 43 | for v in G[u]: 44 | if not visited[v]: 45 | stack.append(v) 46 | level[v] = level[u] + 1 47 | if level[v] == (level[u]+1): #if it has the same length as the previous v 48 | path[v] += path[u] 49 | 50 | 4.6 Assume it is not a tree. 51 | 52 | 4.7 Run Dijkstra's algorithm on the Graph G. then compare the lengths found by both trees. 53 | 54 | 4.8 It is not a valid method since each path gets increased by a different 55 | number depending on the number of edges it has. 56 | 57 | 4.9 Yes, it can. supoose for one of its neighboring edges, it is s->t is 2 58 | 59 | 4.10 60 | Do explore on the edges, K times. 61 | 62 | 4.11 63 | Do a dfs, to check all paths.. if a back edge is encountered then we have a cycle and 64 | check the length of the cycle. 65 | 66 | 4.12 67 | start (u,v) and dfs.. and look for a cycle. 68 | 69 | 4.13 70 | (a) Connect two cities with an undirected edge if le>=L 71 | Then do a bfs or a dfs to determine if t is reachable from s 72 | (b) Find the minimum distance between cities in the path from s to t. 73 | But it can be less I think. do a binary search? 74 | 75 | 4.14 76 | Find the all the shortest paths to v0 and all the shortest paths from v0 77 | 78 | 4.15 79 | Use dijkstra's algorithm.. 80 | if dist[v]==dist[u]+w[(u,v)]: 81 | then usq[s] = True 82 | 83 | 4.16 84 | (a) lol.. it is obvious? 85 | (b) parent is j/d and its children are j*d+i where i is from 0 to d-1 86 | (c) 87 | (d) just ensure that j/d is smaller than every j 88 | 89 | 4.17 90 | (a) make dummy nodes and do a bfs. 91 | (b) 92 | 93 | 4.18 94 | for v in G[u]: 95 | best[v]= min(best[v], best[u]+1) 96 | 97 | 4.19 98 | for v in G[u]: 99 | cost[v] = min(cost[v], cost[u]+w[(u,v)]+c[v]) 100 | 101 | 4.20 102 | Do a shortest path from one of the end of the edge and 103 | Basically, shortest path with new edge e = (u,v) 104 | nshortest[v] = shortest[u]+WithNewEdgeshortest[v] 105 | maxdecrease = max(maxdecrease, shortest[v]-nshortest[v]) 106 | 107 | 4.21 108 | (a) edges should be log(rateab). but is a longest path problem. 109 | I could have just negated the edges but, there are cycles in this 110 | graph. Just do dijkstra's but with a modified condition? 111 | Use a max heap? 112 | for v in G[u]: 113 | if longest[v] dist[u]+w[(u, v)]: 14 | dist[v] = dist[u]+w[(u, v)] 15 | 16 | 17 | G = [[] for i in xrange(10)] 18 | G[0] = [1, 3, 5, 6] 19 | G[1] = [2, 3] 20 | G[2] = [7, 8] 21 | G[3] = [4, 6] 22 | G[5] = [6, 8] 23 | G[6] = [4] 24 | G[7] = [9] 25 | G[8] = [7] 26 | G[9] = [8] 27 | w = {} 28 | w[(1, 2)] = 4 29 | w[(1, 3)] = -2 30 | w[(2, 7)] = -2 31 | w[(2, 8)] = -4 32 | w[(3, 4)] = 2 33 | w[(3, 6)] = 1 34 | w[(5, 8)] = 3 35 | w[(5, 6)] = -2 36 | w[(6, 4)] = 3 37 | w[(7, 9)] = -1 38 | w[(8, 7)] = 1 39 | w[(9, 8)] = 1 40 | w[(0, 1)] = 7 41 | w[(0, 2)] = 6 42 | w[(0, 6)] = 5 43 | w[(0, 5)] = 6 44 | BellmanFord(G, w, 0) 45 | 46 | -------------------------------------------------------------------------------- /code/FastFourier.py: -------------------------------------------------------------------------------- 1 | from math import cos, sin, pi 2 | 3 | 4 | def FFT(A, w): 5 | """A is a polynomial of degree 2^k=n. (pad with zeros if necessary), w is 6 | the kth root of unity. This function takes the coefficent expansion of the 7 | polynomical and returns the value representation of the polynomial 8 | """ 9 | if len(A) == 1: 10 | return A 11 | Aodd = [A[i] for i in xrange(1, len(A), 2)] 12 | Aeven = [A[i] for i in xrange(0, len(A), 2)] 13 | Aoddvalues = FFT(Aodd, w**2) 14 | Aevenvalues = FFT(Aeven, w**2) 15 | Ans = [] 16 | for i in xrange(len(A)/2): 17 | Ans.append(Aevenvalues[i] + w**i * Aoddvalues[i]) 18 | for i in xrange(len(A)/2): 19 | Ans.append(Aevenvalues[i] - w**i * Aoddvalues[i]) 20 | return Ans 21 | 22 | 23 | def form(val): 24 | if abs(val) < 1e-9: 25 | return 0 26 | else: 27 | return int(val+0.5) 28 | 29 | n = 8 30 | w = cos(2*pi / n) + 1j * sin(2*pi / n) 31 | ValueRep1 = FFT([0, 1, 2, 0, 0, 0, 0, 0], w) 32 | ValueRep2 = FFT([2, 3, 8, 0, 0, 0, 0, 0], w) 33 | ValueRep3 = [ValueRep1[i]*ValueRep2[i] for i in xrange(n)] 34 | CoefficientRep3 = FFT(ValueRep3, 1/w) 35 | ans = 0 36 | power = 1 37 | for val in CoefficientRep3: 38 | ans = form(val.real/n)*power+ans 39 | power *= 10 40 | print ans 41 | print [form(val.real/n) for val in CoefficientRep3] 42 | print 210*832 -------------------------------------------------------------------------------- /code/MaxContiguousSubsequence.py: -------------------------------------------------------------------------------- 1 | def solution(A): 2 | prefixSum = [0] * (len(A) + 1) 3 | for i in xrange(len(A)): 4 | prefixSum[i + 1] = prefixSum[i] + A[i] 5 | dp = [0] * len(A) 6 | for i in xrange(len(A)): 7 | maxval = -float('inf') 8 | for j in xrange(i+1): 9 | maxval = max(maxval, prefixSum[i+1] - prefixSum[j]) 10 | dp[i] = maxval 11 | 12 | return max(dp) 13 | 14 | 15 | def solution2(A): 16 | m = [0]*len(A) 17 | m[0] = A[0] 18 | for i in range(1, len(A)): 19 | m[i] = max(m[i-1]+A[i], A[i]) 20 | return max(m) 21 | 22 | print solution([5, 15, -30, 10, -5, 40, 10]) 23 | print solution2([5, 15, -30, 10, -5, 40, 10]) 24 | -------------------------------------------------------------------------------- /code/depthFirstSearch.py: -------------------------------------------------------------------------------- 1 | visited = [False] * 9 2 | pre = [-1] * 9 3 | post = [-1] * 9 4 | G = [[] for i in range(9)] 5 | G[0] = [1, 4] 6 | G[1] = [1, 2, 4] 7 | G[2] = [1, 5] 8 | G[3] = [6, 7] 9 | G[4] = [1, 5] 10 | G[5] = [4, 8] 11 | G[6] = [3, 7] 12 | G[7] = [3, 6] 13 | G[8] = [5] 14 | 15 | num2letter = dict(zip(range(9), 'ABCDEFGHI')) 16 | 17 | 18 | def dfs(G, u): 19 | global clock 20 | global visited 21 | pre[u] = clock 22 | clock += 1 23 | visited[u] = True 24 | print num2letter[u], 25 | for v in G[u]: 26 | if not visited[v]: 27 | dfs(G, v) 28 | post[u] = clock 29 | clock += 1 30 | 31 | """ 32 | clock = 0 33 | for node in range(9): 34 | if not visited[node]: 35 | dfs(G, node) 36 | print 37 | 38 | print pre 39 | print post 40 | """ 41 | # 3.2 New Graph 42 | 43 | G2 = [[] for i in range(8)] 44 | G2[0].append(1) 45 | G2[0].append(5) 46 | G2[1].append(2) 47 | G2[1].append(4) 48 | G2[2].append(3) 49 | G2[3].append(1) 50 | G2[3].append(7) 51 | G2[4].append(3) 52 | G2[4].append(6) 53 | G2[5].append(6) 54 | G2[5].append(4) 55 | G2[6].append(5) 56 | G2[7].append(6) 57 | 58 | G3 = [[] for i in range(8)] 59 | G3[0].append(2) 60 | G3[1].append(2) 61 | G3[2].append(3) 62 | G3[2].append(4) 63 | G3[3].append(5) 64 | G3[4].append(5) 65 | G3[5].append(6) 66 | G3[5].append(7) 67 | 68 | clock = 0 69 | for node in range(8): 70 | if not visited[node]: 71 | dfs(G3, node) 72 | print 73 | print 74 | 75 | print pre 76 | print post -------------------------------------------------------------------------------- /code/dijkstra.py: -------------------------------------------------------------------------------- 1 | from heapq import heapify, heappop, heappush 2 | num2letter = dict(zip(range(14), ' ABCDEFGHIJKLM')) 3 | 4 | 5 | def dij(G, w, u): 6 | """G is a list of edges""" 7 | deletedNodes = set() 8 | stack = [(float('inf'), node) for node in range(len(G))] 9 | stack[u] = (0, u) 10 | dist = [float('inf') for node in range(len(G))] 11 | dist[u] = 0 12 | heapify(stack) 13 | while stack: 14 | du, u = heappop(stack) # hm.. shouldn't this be a priority queue? 15 | while (du, u) in deletedNodes and stack != []: 16 | deletedNodes.remove((du, u)) 17 | du, u = heappop(stack) 18 | for v in G[u]: 19 | if dist[v] > dist[u] + w[(u, v)]: 20 | dv = du + w[(u, v)] 21 | if (du, u) in deletedNodes: 22 | deletedNodes.remove((du, u)) # no longer deleted 23 | else: 24 | heappush(stack, (dv, v)) # push new change 25 | # mark node as deleted 26 | deletedNodes.add((dist[v], v)) 27 | dist[v] = dv 28 | 29 | 30 | G = [[] for i in xrange(9)] 31 | G[1] = [2, 5, 6] 32 | G[2] = [3, 6, 7] 33 | G[3] = [4, 7] 34 | G[4] = [7, 8] 35 | G[5] = [6] 36 | G[7] = [6, 8] 37 | w = {} 38 | w[(1, 2)] = 1 39 | w[(1, 5)] = 4 40 | w[(1, 6)] = 8 41 | w[(2, 3)] = 2 42 | w[(2, 6)] = 6 43 | w[(2, 7)] = 6 44 | w[(3, 4)] = 1 45 | w[(3, 7)] = 2 46 | w[(4, 8)] = 4 47 | w[(4, 7)] = 1 48 | w[(5, 6)] = 5 49 | w[(7, 6)] = 1 50 | w[(7, 8)] = 1 51 | 52 | dij(G, w, 1) 53 | -------------------------------------------------------------------------------- /code/iterDFS.py: -------------------------------------------------------------------------------- 1 | visited = [False] * 11 2 | prev = [-1] * 11 3 | post = [-1] * 11 4 | 5 | # this is wrong somehow.. 6 | 7 | 8 | def dfs(G, u): 9 | global clock 10 | # visited = [False] * 11 11 | stack = [u] 12 | visited[u] = True 13 | # clock = 0 14 | prev[u] = clock 15 | clock += 1 16 | while stack: 17 | u = stack.pop(-1) 18 | print u, 19 | # visited[u] = True 20 | # this post value is wrong. 21 | post[u] = clock 22 | clock += 1 23 | for v in G[u]: 24 | if not visited[v]: 25 | visited[v] = True 26 | stack.append(v) 27 | prev[v] = clock 28 | clock += 1 29 | 30 | G = [[] for i in range(11)] 31 | G[1] = [3, 8] 32 | G[2] = [1, 7] 33 | G[3] = [4] 34 | G[4] = [6] 35 | G[5] = [1, 9] 36 | G[6] = [10] 37 | G[7] = [9] 38 | G[8] = [6, 7] 39 | G[9] = [8] 40 | G[10] = [3] 41 | 42 | clock = 0 43 | for node in xrange(1, 11): 44 | if not visited[node]: 45 | dfs(G, node) 46 | print 47 | print prev 48 | print post 49 | -------------------------------------------------------------------------------- /code/mergesort.py: -------------------------------------------------------------------------------- 1 | def merge(x, y): 2 | # print x,y 3 | if x == []: 4 | return y 5 | if y == []: 6 | return x 7 | if x[0] < y[0]: 8 | return [x[0]] + merge(x[1:], y) 9 | else: 10 | return [y[0]] + merge(x, y[1:]) 11 | 12 | 13 | def mergesort(A): 14 | x = A[:len(A) / 2] 15 | y = A[len(A) / 2:] 16 | if len(A) == 1: 17 | return A 18 | return merge(mergesort(x), mergesort(y)) 19 | 20 | 21 | print mergesort([112, 12, 1, 243, 233, 1, 290, 68]) 22 | 23 | 24 | def itermergesort(A): 25 | q = [[a] for a in A] 26 | while len(q) != 1: 27 | val1 = q.pop(0) 28 | val2 = q.pop(0) 29 | q.append(merge(val1, val2)) 30 | return q[0] 31 | 32 | 33 | print itermergesort([112, 12, 1, 243, 233, 1, 290, 68]) 34 | -------------------------------------------------------------------------------- /code/minimumSpanningTree.py: -------------------------------------------------------------------------------- 1 | def Kruskal(G, n): 2 | """Given an undirected weighted Graph return it's minimum spanning tree 3 | Graph G is represented by a list of edges and weights, 4 | n is the number of nodes""" 5 | parent = [0] * n 6 | rank = [0] * n 7 | 8 | def makeset(A): 9 | "make disjoint where every element is a singleton set" 10 | for a in A: 11 | parent[a] = a 12 | 13 | def find(u): 14 | "find the set u belongs to" 15 | while parent[u] != u: 16 | u = parent[u] 17 | return u 18 | 19 | def union(u, v): 20 | rootu = find(u) 21 | rootv = find(v) 22 | if rank[rootu] > rank[rootv]: 23 | parent[rootv] = rootu 24 | elif rank[u] < rank[v]: 25 | parent[rootu] = rootv 26 | else: 27 | rank[rootu] += 1 28 | parent[rootv] = rootu 29 | makeset(range(n)) 30 | G.sort() 31 | MinSpanTree = []#set() 32 | for edge in G: 33 | w, u, v = edge 34 | if find(u) != find(v): 35 | MinSpanTree.append((w, u, v)) 36 | union(u, v) 37 | return MinSpanTree 38 | 39 | 40 | G = [(1, 1, 5), (6, 1, 2), (2, 2, 5), (1, 5, 6), (5, 2, 3), (6, 3, 4), 41 | (5, 3, 6), (3, 6, 7), (3, 7, 8), (5, 4, 6), (7, 4, 8), (2, 2, 6), 42 | (4, 3, 7)] 43 | minSpanTree = Kruskal(G, 9) 44 | print minSpanTree 45 | print sum([u for u, v, w in minSpanTree]) -------------------------------------------------------------------------------- /code/multilpyDivideAndConquer.py: -------------------------------------------------------------------------------- 1 | 2 | def multiply(a, b): 3 | """numbers a and b represented as binary strings""" 4 | if a == "1": 5 | return b 6 | elif a == "0": 7 | return "0" 8 | else: 9 | m = a[:len(a) / 2] # a>>length/2 10 | n = a[len(a) / 2:] 11 | o = b[:len(b) / 2] # b>>length/2 12 | p = b[len(b) / 2:] 13 | p1 = multiply(m, n) 14 | p2 = multiply(o, p) 15 | p3 = multiply(int(m) + int(n), int(o) + int(p)) 16 | return int(p1) << len(a) + (int(p3) - int(p1) - int(p2)) << (len(a)/2)\ 17 | + int(p2) 18 | -------------------------------------------------------------------------------- /code/multiply.py: -------------------------------------------------------------------------------- 1 | # reference 2 | print 13466 * 3433344 3 | 4 | 5 | def multp(x, y): 6 | """Al Khwarizmi's algorithm""" 7 | ans = 0 8 | while x > 0: 9 | if x & 1 == 1: 10 | ans += y 11 | x /= 2 12 | y *= 2 13 | return ans 14 | 15 | 16 | # test 17 | print multp(13466, 3433344) 18 | 19 | 20 | def multp2(x, y): 21 | """ multiplication ala francais""" 22 | if y == 0: 23 | return 0 24 | else: 25 | if y & 1: 26 | return x + 2 * multp2(x, y / 2) 27 | else: 28 | return 2 * multp2(x, y / 2) 29 | 30 | 31 | # test 32 | print multp2(13466, 3433344) 33 | 34 | 35 | def divide(x, y): 36 | if x == 0: 37 | return (0, 0) 38 | else: 39 | q, r = divide(x / 2, y) 40 | q = 2 * q 41 | r = 2 * r 42 | if x & 1: 43 | r += 1 44 | if r >= y: 45 | r = r - y 46 | q = q + 1 47 | return (q, r) 48 | 49 | 50 | print divide(46233410304, 13466) 51 | -------------------------------------------------------------------------------- /code/primsAlgo.py: -------------------------------------------------------------------------------- 1 | from heapq import heapify, heappop, heappush 2 | 3 | 4 | def primsAlgo(G, u, n): 5 | """G is a list of weighted edges, returns the minimum spanning tree""" 6 | deletedNodes = set() 7 | dist = [float('inf') for node in range(n+1)] 8 | dist[u] = 0 9 | heapify(G) 10 | w = {} 11 | for d, u, v in G: 12 | w[(u, v)] = d 13 | # print w 14 | # print G 15 | nodes = set() 16 | minSpanTree = [] 17 | stack = G 18 | nG = [[] for i in xrange(9)] 19 | for d, u, v in G: 20 | nG[u].append(v) 21 | while len(nodes) != n: 22 | du, u, v = heappop(stack) 23 | # need to check if the node is in the minspantree already 24 | if u not in nodes or v not in nodes: 25 | minSpanTree.append((du, u, v)) 26 | dist[u] = du 27 | nodes.add(u) 28 | nodes.add(v) 29 | while (du, u, v) in deletedNodes and stack != []: 30 | deletedNodes.remove((du, u, v)) 31 | du, u, v = heappop(stack) 32 | for v in nG[u]: 33 | if dist[v] > dist[u] + w[(u, v)]: 34 | dv = du + w[(u, v)] 35 | if (du, u) in deletedNodes: 36 | deletedNodes.remove((du, u)) # no longer deleted 37 | else: 38 | heappush(stack, (dv, u, v)) # push new change 39 | # mark node as deleted 40 | deletedNodes.add((dist[v], v)) 41 | dist[v] = dv 42 | print dist 43 | return minSpanTree 44 | 45 | G = [(1, 1, 5), (6, 1, 2), (2, 2, 5), (1, 5, 6), (5, 2, 3), (6, 3, 4), 46 | (5, 3, 6), (3, 6, 7), (3, 7, 8), (5, 4, 6), (7, 4, 8), (2, 2, 6), 47 | (4, 3, 7)] 48 | 49 | print primsAlgo(G, 0, 8) 50 | -------------------------------------------------------------------------------- /code/priorityQueue.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | 4 | class PQueue(object): 5 | """Priority Queue representation using a binary heap""" 6 | def __init__(self): 7 | self.arr = [] 8 | 9 | def pop(self): 10 | mini = self.arr[0] # the min is always the first item in the array 11 | self.arr[0] = self.arr.pop(-1) 12 | self._bubbledown() 13 | 14 | def push(self, x): 15 | self.arr.append(x) 16 | self._bubbleup() 17 | 18 | def _swap(self, i, j): 19 | temp = self.arr[i] 20 | self.arr[i] = self.arr[j] 21 | self.arr[j] = temp 22 | 23 | @staticmethod 24 | def _parent(x): 25 | return (x-1)/2 26 | 27 | def _bubbleup(self): 28 | index = len(self.arr)-1 # bubble up from the last position 29 | while index > 0 and self.arr[self._parent(index)] > self.arr[index]: 30 | # while not at the top and the parent is not the root. 31 | # swap 32 | self._swap(index, self._parent(index)) 33 | index = self._parent(index) 34 | 35 | def _minchild(self, index): 36 | left = 2*index+1 37 | right = 2*index+2 38 | if self.arr[right] > self.arr[left]: 39 | return left 40 | else: 41 | return right 42 | 43 | def _bubbledown(self): 44 | 45 | c = self._minchild(0) 46 | i = 0 47 | while c < len(self.arr) and self.arr[c] < self.arr[i]: 48 | self._swap(i, c) 49 | index = c 50 | c = self._minchild(c) 51 | 52 | 53 | class TestCase(unittest.TestCase): 54 | def setUp(self): 55 | self.Queue = PQueue() 56 | arr = [23, 35, 13, 34, 13, 5, 7, 12, 54] 57 | for a in arr: 58 | self.Queue.push(a) 59 | 60 | def test_min(self): 61 | self.assertEqual(min(self.Queue.arr), self.Queue.arr[0]) 62 | 63 | def test_minAfterPop(self): 64 | self.Queue.pop() 65 | self.assertEqual(min(self.Queue.arr), self.Queue.arr[0]) 66 | self.Queue.pop() 67 | self.Queue.pop() 68 | self.assertEqual(min(self.Queue.arr), self.Queue.arr[0]) 69 | 70 | def test_minAfterPopPush(self): 71 | self.Queue.pop() 72 | self.Queue.push(0) 73 | self.assertEqual(min(self.Queue.arr), self.Queue.arr[0]) 74 | 75 | def test_minAfterPopPushPop(self): 76 | pass 77 | 78 | def test_EnsureChildrenAlwaysGreaterThanParents(self): 79 | """test recurcisively :). It is a tree afterall""" 80 | 81 | 82 | if __name__ == "__main__": 83 | unittest.main() 84 | -------------------------------------------------------------------------------- /code/recursivefunction.py: -------------------------------------------------------------------------------- 1 | def f(n): 2 | if n > 1: 3 | print 'going', n 4 | f(n / 2) 5 | f(n / 2) 6 | 7 | 8 | f(16) 9 | print 'here' 10 | -------------------------------------------------------------------------------- /code/stronglyConnectComponent.py: -------------------------------------------------------------------------------- 1 | num2letter = dict(zip(range(14), ' ABCDEFGHIJKLM')) 2 | clock = 0 3 | 4 | 5 | def dfs(G, n): 6 | global clock 7 | visited = [False] * (n + 1) 8 | pre = [-1] * (n + 1) 9 | post = [-1] * (n + 1) 10 | order = [] 11 | clock = 0 12 | 13 | def dfsVisit(G, u): 14 | global clock 15 | pre[u] = clock 16 | clock += 1 17 | visited[u] = True 18 | # print num2letter[u], 19 | for v in G[u]: 20 | if not visited[v]: 21 | dfsVisit(G, v) 22 | post[u] = clock 23 | order.append(u) 24 | clock += 1 25 | 26 | for node in xrange(1, n + 1): 27 | if not visited[node]: 28 | dfsVisit(G, node) 29 | return order 30 | 31 | 32 | def getSCC(G, n): 33 | component = [0] * (n + 1) 34 | 35 | def dfsVisit(G, u, c): 36 | visited[u] = True 37 | component[u] = c 38 | s.add(num2letter[u]) 39 | for v in G[u]: 40 | if not visited[v]: 41 | dfsVisit(G, v, c) 42 | order = dfs(G, n) 43 | visited = [False] * (n + 1) 44 | c = 0 45 | for node in order: 46 | if not visited[node]: 47 | s = set() 48 | c += 1 49 | dfsVisit(G, node, c) 50 | print s 51 | return component 52 | 53 | 54 | G = [[] for i in range(11)] 55 | G[1] = [3, 8] 56 | G[2] = [1, 7] 57 | G[3] = [4] 58 | G[4] = [6] 59 | G[5] = [1, 9] 60 | G[6] = [10] 61 | G[7] = [9] 62 | G[8] = [6, 7] 63 | G[9] = [8] 64 | G[10] = [3] 65 | 66 | print getSCC(G, 10) 67 | --------------------------------------------------------------------------------