Algoritma yang luar biasa cepat

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:











an+k+1=i=1kcian+i







Pertama k elemen urutan dianggap sudah diberikan. Jumlah k disebut kardinalitas urutan, dan ci koefisien urutan. Contoh umum: angka Fibonacci, di mana a1=0 , a2=1 , c1=1 , c2=1 ... 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 an saat ereksi n - - ? , ? , an+2 ? an an+1 . , , . - "" . ? : ! , , ?







, ! :







A=(1110)







, an+1=A1,1n . , !







, ? ? , :







(fn+1fnfnfn1)×(1110)=(fn+2fn+1fn+1fn)







, " " . . A . "":











t1=1t2=1t3=1...tn+3=tn+2+tn+1+tn







A :







(110101100)







? , . , . :







(tn+2tn+1tntn+1tntn1tntn1tn2)×(110101100)=(tn+3tn+2tn+1tn+2tn+1tntn+1tntn1)







, T :







(t5t4t3t4t3t2t3t2t1)=(311111110)







tn+2=(T×An1)1,1 . , A n1 , T A . T A .







, k :







(c11000c20100c30010ck0001)







, , 2k1 , "" .







, O(k3logn) : O(k3) , O(logn) . . , , n44 , n208 . \ , . , n118 .







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. .







T A , 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)
      
      





n — , . , , , - . , , .









: A[1..n]



( ). A[i..j]



. i



j



. , O(n3) , O(n2) , O(nlogn) O(n) .







:







  1. . , . . , .
  2. . , .
  3. O(nlogn) . , : , , .
  4. 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:







  1. k < 0



    ... Maka 0 akan mengungguli k



    yang pertama max



    .
  2. k = 0



    ... Pada max



    argumen pertama , Anda cukup menghapus argumen kedua.
  3. k > 0



    ... Lalu max{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?








All Articles