Lista 3, Zadanie 4

by Jerry Sky



Problem

Definiujemy Gn={0if n=01if n=11if n=2Gn1+Gn2+Gn3if n3 G_n = \begin{cases} &&0 & \mathrm{if}~n=0\\ &&1 & \mathrm{if}~n=1\\ &&1 & \mathrm{if}~n=2\\ &&G_{n-1} + G_{n-2} + G_{n-3} & \mathrm{if}~n\ge3\\ \end{cases} Jest to ciąg generowany rekursywnie na podstawie ziarna (seed-a) w postaci trzech pierwszych wyrazów.

Concept (bottom-up)

Analogicznie jest w przypadku ciągu Fibonacciego, który definiujemy następująco: Fn={0if n=01if n=1Fn1+Fn2oth. F_n = \begin{cases} &&0 & \mathrm{if}~n=0\\ &&1 & \mathrm{if}~n=1\\ &&F_{n-1} + F_{n-2} & \text{oth.} \end{cases}

Jednakże możemy zapisać ciąg Fibonacciego w sposób macierzowy: [1110]n=[Fn+1FnFnFn1] \begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix}^n = \begin{bmatrix} F_{n+1} & F_n\\ F_{n} & F_{n-1} \end{bmatrix} [Fn+1FnFnFn1]×[1110]=[Fn+2Fn+1Fn+1Fn] \begin{bmatrix} F_{n+1} & F_n\\ F_{n} & F_{n-1} \end{bmatrix} \times \begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix} = \begin{bmatrix} F_{n+2} & F_{n+1}\\ F_{n+1} & F_{n} \end{bmatrix}

Dla naszego problemu GnG_n również musimy znaleźć odpowiednią macierz, którą po podniesieniu do odpowiedniej potęgi uzyskamy dostęp do nn-tego wyrazu ciągu GG.

Rozwiązanie

Musimy znaleźć taką macierz AA, że: [GnGn1Gn2]=A×[Gn1Gn2Gn3] \begin{bmatrix} G_n\\ G_{n-1}\\ G_{n-2}\\ \end{bmatrix} = A\times \begin{bmatrix} G_{n-1}\\ G_{n-2}\\ G_{n-3}\\ \end{bmatrix}

Czyli, żeby otrzymać rekurencję Gn=Gn1+Gn2+Gn3G_n = G_{n-1} + G_{n-2} + G_{n-3} pierwszy wiersz AA musi wynosić A1=[ 1  1  1 ]A_1 = [~1~~1~~1~].
W przypadku wierszy A2A_2 oraz A3A_3 wystarczy „przepisać” wartości Gn1G_{n-1} oraz Gn2G_{n-2}. Więc wystarczy zrobić prostą mapę bitową przenoszącą te wartości do macierzy po prawej stronie. Dlatego też: A=[111100010] A = \begin{bmatrix} 1 & 1 & 1\\ 1 & 0 & 0\\ 0 & 1 & 0\\ \end{bmatrix}

[111100010]2=[221111100] \begin{bmatrix} 1 & 1 & 1\\ 1 & 0 & 0\\ 0 & 1 & 0\\ \end{bmatrix}^2 = \begin{bmatrix} 2 & 2 & 1\\ 1 & 1 & 1\\ 1 & 0 & 0\\ \end{bmatrix} [111100010]3=[432221111] \begin{bmatrix} 1 & 1 & 1\\ 1 & 0 & 0\\ 0 & 1 & 0\\ \end{bmatrix}^3 = \begin{bmatrix} 4 & 3 & 2\\ 2 & 2 & 1\\ 1 & 1 & 1\\ \end{bmatrix} i ogólnie [111100010]n=[GnGn1+Gn2Gn1Gn1Gn2+Gn3Gn2Gn2Gn3+Gn4Gn3] \begin{bmatrix} 1 & 1 & 1\\ 1 & 0 & 0\\ 0 & 1 & 0\\ \end{bmatrix}^n = \begin{bmatrix} G_n & G_{n-1} + G_{n-2} & G_{n-1}\\ G_{n-1} & G_{n-2} + G_{n-3} & G_{n-2}\\ G_{n-2} & G_{n-3} + G_{n-4} & G_{n-3} \end{bmatrix} przy czym, żeby nie mieć problemu z określeniem liczb dla ujemnych indeksów (np. co to jest Gn4G_{n-4} kiedy mamy n=3n=3 ?) ustalimy macierz początkową X=[111100010]3=[432221111]=[G4G3+G2G3G3G2+G1G2G2G1+G0G1] X = \begin{bmatrix} 1 & 1 & 1\\ 1 & 0 & 0\\ 0 & 1 & 0\\ \end{bmatrix}^3 = \begin{bmatrix} 4 & 3 & 2\\ 2 & 2 & 1\\ 1 & 1 & 1\\ \end{bmatrix} = \begin{bmatrix} G_4 & G_3 + G_2 & G_3\\ G_3 & G_2 + G_1 & G_2\\ G_2 & G_1 + G_0 & G_1\\ \end{bmatrix} którą będziemy przemnażać przez macierz AA celem uzyskania kolejnych wyrazów ciągu GnG_n.

W takim układzie mamy na samym początku już policzone wyrazy od G0G_0 do G4G_4 a następne wyrazy będziemy uzyskiwali przez mnożenie macierzy XX przez AA.

Teraz, problemem jest osiągnięcie złożoności obliczeniowej T(n)=O(lgn)T(n) = O(\lg n) przy przemnażaniu macierzy XX przez AA.
Należy zauważyć, że w ogólnym przypadku nie ma przemienności w mnożeniu macierzy. Tutaj jednak, operujemy na potęgach tak naprawdę jednej macierzy co daje nam przemienność.

Przy przemnażaniu naszej „macierzy atomowej” AA nie należy się też martwić o złożoność, ponieważ za każdym razem jest to macierz o 3 kolumnach i 3 wierszach.

Można użyć algorytmu analogicznego do liczenia potęg liczb naturalnych w czasie O(lgn)O(\lg n).

Nasz algorytm działałby następująco:

  1. Jeśli n{0,,4}n\in\{0,\dots,4\} zwróć zapisaną wartość.
  2. W przeciwnym wypadku oblicz n4n-4 potęgę macierzy AA przy pomocy poniższej funkcji power_matrix, pomnóż wynik przez XX i go zwróć.

Liczenie potęgi macierzy w czasie O(lgn)O(\lg n)

Zdefiniujemy funkcję PowerMatrix(A,k)(A, k):

  1. output = [100010001]\begin{bmatrix}1&0&0\\0&1&0\\0&0&1\end{bmatrix}
  2. while k>0k>0:
    1. if 2∤ k2\not|~k:
      1. output *= AA
    2. k=k2k = \lfloor\frac{k}{2}\rfloor
    3. A=A2A = A^2
  3. return output