ECE 606, Fall 2019, Assignment 5: Zhijie Wang, Student ID Number: 20856733 Zhijie - Wang@uwaterloo - Ca October 8, 2019
ECE 606, Fall 2019, Assignment 5: Zhijie Wang, Student ID Number: 20856733 Zhijie - Wang@uwaterloo - Ca October 8, 2019
[email protected]
October 8, 2019
2. Let’s denote the equivalence tester as CheckEquivalent(x, y), where x, y are two account numbers, and
it will return T rue if equivalent and F alse else. Assume the number of n cards are stored in an array
A[0, 1, . . . , n − 1] with size n.
HalfEquivalent(A)
1: if HalfCheck(A, 0, n − 1) 6= N one then
2: return T rue
3: else
4: return F alse
HalfCheck(A, p, r)
1: while r − p + 1 > 3 do
2: q ← b(p + r)/2c
3: m1 ←HalfCheck(A, p, q)
4: m2 ←HalfCheck(A, q + 1, r)
5: return CheckValid(A, p, r, m1 , m2 )
6: return CheckValid(A, p, r, p, r)
1
CheckValid(A, p, r, m1 , m2 )
1: if CheckCount(A, p, r, m1 ) then
2: return m1
3: else if CheckCount(A, p, r, m2 ) then
4: return m2
5: else
6: return N one
CheckCount(A, p, r, m)
1: if m = N one then
2: return F alse
3: count ← 0
4: for i from p to r do
5: if CheckEquivalent(A[m], A[i]) then
6: count ← count + 1
7: if count > b(r − p + 1)/2c then
8: return T rue
9: else
10: return F alse
Here we give a brief analysis about the algorithm above. The basic idea is that if there is a number
appears more than half of size’s times in an array, then, this number will still appears more than half of
size’s times in one of arrays which is half of the original array. Therefore, HalfCheck will be invoked
log n times until there are several arrays which has a size of 2 or 3. Then, we invoke CheckValid to
check if there is a number appears more than half of size’s times in each array. And combine the result
of each two arrays, then, check again. Finally, HalfCheck will return a value, if it is not N one, then,
there is such a number appears.
In the worst-case, HalfCheck will be invoked log n times, and each one takes O(n) times to search for
m1 and m2 . Therefore, it needs O(n log n) times of comparisons.
And I think there is another algorithm which only need O(n) comparisons. Here is the pseudo-
code.
HalfEquivalent(A)
1: count ← 1
2: cur ← A[0]
3: for i from 1 to n − 1 do
4: if count = 0 then
5: cur ← A[i]
6: count ← 1
7: else if CheckEquivalent(cur, A[i]) then
8: count ← count + 1
9: else
10: count ← count − 1
11: count ← 0
12: for i from 0 to n − 1 do
13: if CheckEquivalent(cur, A[i]) then
14: count ← count + 1
15: if count > bn/2c then
16: return T rue
17: else
18: return F alse
Now we give a brief analysis on the algorithm above. Assume an account number appears more than n/2
times in n cards, let’s denote the times of appearance as m. Then, m should bigger than the sum of any
other number’s appearances. Every time we select a new cur in Line(4) to Line(6), which means that if
there is no number appears more than half of size’s times before, and we only need to search if there is
a number appears more than half of size’ times after this selection, then say it is cur. (But this number
might not appears more than half of size’s times in the whole array.)
Hence, when the first for-loop ends, if such account number exits, than cur should be this number (Note
2
that here we do not need to copy the value to cur, but only the address, which is similar as a pointer
operation in C++). But actually this number might not exist, so we invoke another for-loop to ensure
that this number’s appearance times is bigger than n/2. In the worst-case we invoke the tester (2n − 1)
times, therefore, our algorithm do comparison only O(n) times.
3. (a) The basic idea of proposed algorithm is to search the minimum numbers of each value. Here we
denote the number of coins of each value is [m0 , m1 , . . . , mn−1 ]. And let’s start from C0 ∈ C =
[C0 , C1 , C2 , . . . Cn−1 ]. And we use the binary search between [0, MinNumCoins(C, a)] for m0 , only
if m0 + MinNumCoins(C[1 :], a − m0 ∗ c0 ) = MinNumCoins(C, a) , then, the m0 is exactly one of
the correct answers. Therefore, for m1 , we only need to search where {C = C[1 : ], a = a − m0 ∗ C0 }.
And in the worst-case, assume the input size is < n = len(C), a = 2s >, therefore the running-time
should be Θ(n log a) = Θ(ns), which is polynomial-time complexity.
Here is the pseudo code about this algorithm. (Length returns the length of list.)
MinCoinsList(C, a)
1: if Length(C) = 1 then
2: return [MinNumCoins(C, a)]
3: C1 ← C.copy()
4: for i from 1 to (Length(C)−1) do
5: result[i] ← BinSearch(C1 , C[i], 0, MinNumCoins(C1 , a), a)
6: a ← a − result[i] ∗ C[i]
7: C1 ← C[j : ]
8: result[Length(C)] ← MinNumCoins(C, a) − Sum(result)
9: return result
BinSearch(C, v, p, r, a)
1: C1 ← C.copy()
2: C1 ← C1 [1 : ]
3: while p <= r do
4: med ← b(p + r)/2c
5: if med + MinNumCoins(C1 , (a − med ∗ v)) = MinNumCoins(C, a) then
6: return med
7: else if med + MinNumCoins(C, (a − med ∗ v)) = MinNumCoins(C, a) then
8: p ← med + 1
9: else
10: r ← med − 1
(b) a5p3b.py