Saat belajar pemrograman, saya menemukan contoh algoritma yang tidak mungkin. Intuisi mengatakan bahwa ini tidak mungkin, tetapi komputer membantahnya hanya dengan menjalankan kode. Bagaimana masalah seperti itu, yang membutuhkan biaya kubik minimum pada waktunya, diselesaikan hanya dalam persegi? Dan yang itu saya pasti akan memutuskan untuk baris itu. Apa? Apakah ada algoritma logaritma yang jauh lebih efisien dan elegan? Luar biasa!
Dalam artikel ini saya akan menyajikan beberapa dari algoritma "pemecah pola" ini, yang menunjukkan bahwa intuisi dapat sangat melebih-lebihkan kompleksitas waktu suatu masalah.
Menarik? Selamat datang di bawah potongan!
Perhitungan elemen ke-n dari urutan berulang dalam logaritma
Yang saya maksud dengan "berulang" adalah urutan yang memenuhi persamaan berikut:
Pertama elemen urutan dianggap sudah diberikan. Jumlah disebut kardinalitas urutan, dan koefisien urutan. Contoh umum: angka Fibonacci, di mana , , , ... Kita mendapatkan angka-angka terkenal: 0, 1, 1, 2, 3, 5, 8, 13, ... Sepertinya tidak ada kesulitan dalam menghitung elemen ke-n per baris, tetapi ternyata bisa dilakukan untuk logaritma!
Ide: bagaimana jika Anda membayangkan sebuah komputasi saat ereksi - - ? , ? , ? . , , . - "" . ? : ! , , ?
, ! :
,
, ? ? , :
, " " . .
? , . , . :
,
,
, ,
,
Matrix :
class Matrix:
def __init__(self, n):
self.n = n
self.rows = [[0 for col in range(n)] for row in range(n)]
def set(self, row, col, value):
self.rows[row][col] = value
def get(self, row, col):
return self.rows[row][col]
def __str__(self):
result = ''
for row in self.rows:
result += ' '.join([str(col) for col in row])
result += '\n'
return result
def __mul__(self, other):
result = Matrix(self.n)
for row in range(self.n):
for col in range(self.n):
s = sum([self.get(row, k) * other.get(k, col) for k in range(self.n)])
result.set(row, col, s)
return result
def __len__(self):
return self.n
def __pow__(self, k):
if k == 0:
result = Matrix(len(self))
for i in range(len(self)):
result.set(i, i, 1)
elif k == 1:
result = self
elif k == 2:
result = self * self
else:
rem = k % 3
prev = self.__pow__((k - rem) // 3)
result = prev * prev * prev
if rem:
result *= self.__pow__(rem)
return result
__pow__
: M ** k
, M
Matrix
. , 3. .
Matrix
:
A = Matrix(3)
A.set(0, 0, 1)
A.set(0, 1, 1)
A.set(1, 0, 1)
A.set(1, 2, 1)
A.set(2, 0, 1)
T = Matrix(3)
T.set(0, 0, 3)
T.set(0, 1, 1)
T.set(0, 2, 1)
T.set(1, 0, 1)
T.set(1, 1, 1)
T.set(1, 2, 1)
T.set(2, 0, 1)
T.set(2, 1, 1)
T.set(2, 2, 0)
n = int(sys.argv[1])
if n:
print(T * A ** (n - 1))
else:
print(T ** 0)
: A[1..n]
( ). A[i..j]
. i
j
. ,
:
- . , . . , .
- . , .
-
. , : , , .O ( n log n ) -
.O ( n ) T[1..n]
,i
- ,i
. , ,T .T
. , T[i + 1]
, T[i]
? , i
, , . , T[i + 1]
T[i] + A[i + 1]
, A[i + 1]
, 0, A[i + 1] < 0
. :
T[0] = 0, T[i + 1] = max{T[i] + A[i + 1], A[i + 1], 0} = max{T[i] + A[i + 1], 0}
Mari kita buktikan persamaan terakhir. Jelas T[i] >= 0
bagi siapa pun i
. Biarkan k = A[i + 1]
. Pertimbangkan tiga kasus:
k < 0
... Maka 0 akan mengunggulik
yang pertamamax
.k = 0
... Padamax
argumen pertama , Anda cukup menghapus argumen kedua.k > 0
... Lalumax{T[i] + k, k, 0} = T[i] + k = max{T[i] + k, 0}
.
Karena linearitas dan kesederhanaan persamaan, algoritme ini cukup singkat:
def kadane(ints):
prev_sum = 0
answer = -1
for n in ints:
prev_sum = max(prev_sum + n, 0)
if prev_sum >= answer:
answer = prev_sum
return answer
Kesimpulan
Dalam kedua tugas tersebut, teknik pemrograman dinamis membantu kami meningkatkan kinerja secara kualitatif. Ini bukan kebetulan, dinamika sering kali memberikan algoritme yang optimal secara asimtotik berkat ekonomi bawaan: kami hanya menghitung semuanya sekali.
Algoritme menakjubkan apa yang Anda ketahui?