monge array是一個矩陣,滿足第j行的最小值的列號C(j)大於等於第i行的最小值的列號C(i),當j>=i的時候,有如下特性
-- 對於任何行列,正對角線的和<=反對角線的和
#!/usr/bin/python
'''file name: monge.py
--P111
--input one m*n monge array, find leftmost minimum value, O(m + nlgm)
--author: zevolo, 2012.05.16
proof:
first to guees the result:
T(m,n) = T(m/2, n) + theta(m + n)
use the recurrence tree:
T(m, n) = c(m + n) + c(m/2 + n) + c(m/4 + n) + ... + c(m/(2^(lgm-1)) + n)
= cm (1+1/2+1/4+...+1/(2^(lgm-1))) + cnlgm
= cm 2(1 - 1/(2^lgm)) + cnlgm
then
assume T(m, n) <= am + bnlgm (a, b are constant)
T(m,n) = T(m/2, n) + c(m+n)
<= (am/2 + bnlg(m/2)) + c(m+n)
= am + bnlgm - am/2 - bn + cm + cn
= am + bnlgm + (c - a/2)m + (c - b)n
'''
def find_odd_min(l, m, n, r):
start = 0
end = 0
ret = []
r.append(n - 1) #sentinel
for i in range(0, m):
k = i / 2
if i % 2 == 0:
ret.append(r[k])
else:
end = r[k+1]
pos = start
val = l[i][pos]
for j in range(start + 1, end + 1):
if l[i][j] < val:
val = l[i][j]
pos = j
start = end
ret.append(pos)
return ret
def find_min(l, m, n):
if m == 1:
pos = 0
val = l[0][0]
for i in range(1, n):
if val > l[0][i]:
pos = i
val = l[0][i]
r = [pos]
return r
sub = []
for i in range(0, m, 2):
sub.append(l[i])
r = find_min(sub, (m+1)/2, n)
ret = find_odd_min(l, m, n, r)
return ret
if __name__ == '__main__':
l = [ [10, 17, 13, 28, 23],
[17, 22, 16, 29, 23],
[24, 28, 22, 34, 24],
[11, 13, 6, 17, 7],
[45, 44, 32, 37, 23],
[36, 33, 19, 21, 6],
[75, 66, 51, 54, 34]
]
r = find_min(l, 6, 5)
print l
print r