Сложность времени для очень сложного кода рекурсии

У меня есть проблема при попытке рассчитать сложность времени для этого кода:

function foo (int a):
    if a < 1: 
        return 1
    else:
        for i = 1 to 4:
            foo(a - 3)
        for i = 1 to 4:
            foo(a / 2)
end function

Насколько я могу идти:

T(n) = 1 if n<1

T(n) = 4T(n-3) + 4T(n/2)     if n>=1

     = 4(4T(n-6) + 4T((n-3)/2))  +  4(4T(n/2 - 3) + 4T(n/4))

     ~ 4^2 (T(n-6) + T((n-3)/2) + T(n/2-3) + T(n/4))

Теперь это очень сложно, так как число следующего увеличения T на 2 ^ n, а также ребенка довольно сложно.

Есть ли другие способы решения этой проблемы?

Ответ 1

Позвольте развернуть функцию рекурсивной стоимости:

T(n) = 4   [T(n-3) + T(n/2)]
T(n) = 4^2 [T(n-6) + T((n-3)/2) + T((n-6)/2) + T(n/4)]
T(n) = 4^n [T(n-9) + 2*T((n-6)/2) + T((n-9)/2) + T((n-12)/4) + T((n-3)/4) + T((n-6)/4) + T(n/8)]

С момента, когда x в T(x) опускается ниже 1, вы должны заменить T(x) на 1. И с этого момента T(x) больше не генерирует никаких "детей".

что это значит? Это означает, что после k -ного расширения T(n) функция будет выглядеть так:

T(n) = 4^k [number of paths with length `k`]

и продолжайте увеличивать k до тех пор, пока все пути не "умерли". Это определенно имеет место после n/3 итераций, потому что это самый длинный путь.

Таким образом, мы имеем некоторый вид графика, например, для n=9:

9 + 6 + 3 + 0
  |   |   ` 1
  |    `3 + 0
  |       ` 1
   `4 + 1
      ` 2 + -1
         `  1

so 6. Теперь проблема состоит в том, как подсчитать количество путей. Для этого мы сначала представляем основной путь: n, n-3, n-6 и т.д. Как горизонтальную линию узлов, это, безусловно, самый длинный путь:

n    n-3  n-6  n-9  ...  1

Теперь из всех этих узлов создайте узлы я → i/2 (кроме одного)

n    n-3      n-6      n-9     ...   4   1
|     |        |         |
n/2  (n-3)/2  (n-6)/2  (n-9)/2 ...   2

(вторая строка показывает все узлы, созданные делениями на 2). Теперь эти узлы генерируют снова offsprong n → n-3, то есть, поскольку он делится на два n/2 → (n-6)/2, другими словами, существуют ребра, которые совершают прыжки из двух:

n    n-3      n-6      n-9     ...   4   1
|     |  /-----+-------(n-9)/2       |
n/2  (n-3)/2  (n-6)/2  (n-9)/2 ...   2
  \---------->(n-6)/2 \------->...

другими словами, за исключением первых двух элементов, все остальные узлы во второй строке подсчитываются для двух. Если бы мы представляли его как некоторый граф с узлами, помеченными их весом, это выглядело бы так:

   1 -- 1 -- 1 -- 1 -- 1 -- .. -- .. -- 1
   |    |    |    |    |    |     |
   1 -- 1 -- 2 -- 2 -- 2 -- .. -- 2

Или если мы продолжаем делать это для этого процесса:

   1 -- 1 -- 1 -- 1 -- 1 -- .. -- .. -- .. -- .. -- ..-- 1
   |    |    |    |    |    |     |     |     |     |
   1 -- 1 -- 2 -- 2 -- 2 -- .. -- .. -- .. -- .. -- 2
   |    |    |    |    |    |     |     |
   1 -- 1 -- 2 -- 2 -- 3 -- .. -- .. -- 4

(третья строка дополнительно создает дочерние элементы 4)

Теперь нам нужно вычислить сумму последней строки. Это самое большее O(log n).

Это приводит к верхней границе максимума O(4^(n/3)*log n). Вполне возможно, что граница более жесткая, или 4 ^ (n/3 + epsilon), log не имеет большого значения, когда дело доходит до экспоненты.

<сильные > Эксперименты

Можно превратить программу в программу, которая вычисляет стоимость (используется Python):

def memodict(f):
    """ Memoization decorator for a function taking a single argument """
    class memodict(dict):
        def __missing__(self, key):
            ret = self[key] = f(key)
            return ret
    return memodict().__getitem__

@memodict
def foo (a):
  if a < 1:
    return 1
  else:
    return 1+4*(foo(a-3)+foo(a//2))

for i in range(1000) :
    print '{0} {1}'.format(i,foo(i))

ум 1+ (это связано с тем, что вызов метода не на листьях требует также вычислительной стоимости).

Здесь показан следующий график (с осью y в лог-пространстве):

график сложности

Если посмотреть очень внимательно, то выглядит, что log n является лучшей оценкой. Хотя я не знаю, можно ли сказать это.

Это приводит к таблице (ниже, вычислено далее до 2'000).

1 9
2 41
3 41
4 201
5 329
6 329
7 969
8 2121
9 2121
10 5193
11 9801
12 9801
13 22089
14 43081
15 43081
16 96841
17 180809
18 180809
19 395849
20 744009
21 744009
22 1622601
23 3015241
24 3015241
25 6529609
26 12149321
27 12149321
28 26290761
29 48769609
30 48769609
31 105335369
32 195465801
33 195465801
34 422064713
35 782586441
36 782586441
37 1688982089
38 3131929161
39 3131929161
40 6758904393
41 12530692681
42 12530692681
43 27038593609
44 50129261129
45 50129261129
46 108166435401
47 200529105481
48 200529105481
49 432677802569
50 802142540361
51 802142540361
52 1730759807561
53 3208618758729
54 3208618758729
55 6923087827529
56 12834580197961
57 12834580197961
58 27692546388553
59 51338515870281
60 51338515870281
61 110770380632649
62 205354484822601
63 205354484822601
64 443082304393801
65 821418721153609
66 821418721153609
67 1772329999438409
68 3285676572873289
69 3285676572873289
70 7089323128099401
71 13142709421838921
72 13142709421838921
73 28357295642743369
74 52570844443284041
75 52570844443284041
76 113429195098690121
77 210283390300852809
78 210283390300852809
79 453716792922477129
80 841133588239028809
81 841133588239028809
82 1814867221812679241
83 3364534403078885961
84 3364534403078885961
85 7259468937373487689
86 13458137720469918281
87 13458137720469918281
88 29037875950010995273
89 53832551082396717641
90 53832551082396717641
91 116151504000561025609
92 215330204762252612169
93 215330204762252612169
94 464606016804360524361
95 861320819851126870601
96 861320819851126870601
97 1858424068019558519369
98 3445283281135218692681
99 3445283281135218692681
100 7433696275286804238921
101 13781133127749444932169
102 13781133127749444932169
103 29734785104355787117129
104 55124532517920818958921
105 55124532517920818958921
106 118939140430257623503433
107 220498130084517750870601
108 220498130084517750870601
109 475756561733864969048649
110 881992520365763354792521
111 881992520365763354792521
112 1903026246986798196986441
113 3527970081514391739961929
114 3527970081514391739961929
115 7612104987998531108737609
116 14111880326168337145401929
117 14111880326168337145401929
118 30448419952199478498431561
119 56447521304878702645088841
120 56447521304878702645088841
121 121793679809003268057207369
122 225790085219957892102885961
123 225790085219957892102885961
124 487174719236834490168119881
125 903160340880652986350834249
126 903160340880652986350834249
127 1948698876948159378611769929
128 3612641363524384274620912201
129 3612641363524384274620912201
130 7794795507795923189331694153
131 14450565454100822773368263241
132 14450565454100822773368263241
133 31179182031186978432211391049
134 57802261816410380413470806601
135 57802261816410380413470806601
136 124716728124761056435137057353
137 231209047265654664360174719561
138 231209047265654664360174719561
139 498866912499057368446839722569
140 924836189062647014733211275849
141 924836189062647014733211275849
142 1995467649996282044625046245961
143 3699344756250640629770532459081
144 3699344756250640629770532459081
145 7981870599985180749337872339529
146 14797379025002675948264700809801
147 14797379025002675948264700809801
148 31927482399940933280729262494281
149 59189516100010914076436576375369
150 59189516100010914076436576375369
151 127709929599763943406294823113289
152 236758064400044110022526700261961
153 236758064400044110022526700261961
154 510839718399056614758740495864393
155 947032257600177281223668004459081
156 947032257600177281223668004459081
157 2043358873596227300168523186868809
158 3788129030400710939761843707744841
159 3788129030400710939761843707744841
160 8173435494384912565208445703590473
161 15152516121602847123581727787094601
162 15152516121602847123581727787094601
163 32693741977539653625368135770477129
164 60610064486411395753795798399095369
165 60610064486411395753795798399095369
166 130774967910158627959610155397452361
167 242440257945645596473320805911925321
168 242440257945645596473320805911925321
169 523099871640634525296578233905353289
170 969761031782582414931158973141652041
171 969761031782582414931158973141652041
172 2092399486562538155018863817501086281
173 3879044127130329713557186774446281289
174 3879044127130329713557186774446281289
175 8369597946250152673908006151884018249
176 15516176508521318970380250897829106249
177 15516176508521318970380250897829106249
178 33478391785000610910962228937122943561
179 62064706034085276096851207920903295561
180 62064706034085276096851207920903295561
181 133913567140002443859179120078078644809
182 248258824136341104852010847685857284681
183 248258824136341104852010847685857284681
184 535654268560009776298037299361325027913
185 993035296545364420269364209792439587401
186 993035296545364420269364209792439587401
187 2142617074240039106053470016494310560329
188 3972141186181457682935880906387200447049
189 3972141186181457682935880906387200447049
190 8570468296960156427659163345381749723721
191 15888564744725830735188806904953309270601
192 15888564744725830735188806904953309270601
193 34281873187840625714081936660931506377289
194 63554258978903322948188923891891471159881
195 63554258978903322948188923891891471159881
196 137127492751362502870108879768266900279881
197 254217035915613291806536828692106759410249
198 254217035915613291806536828692106759410249
199 548509971005450011494216652197608475890249
200 1016868143662453167255882099869574254596681

Ответ 2

(Переписано, чтобы дать лучший ответ.)

Вот простой и строгий анализ, который показывает, почему T(n) ~ 4^{n/3} является плотной оценкой.

Мы имеем рекуррентность

T(n) = 4T(n-3) + 4T(n/2)

Чтобы получить плотный результат, мы хотим видеть, что T(n/2) пренебрежимо мала по сравнению с T(n-3). Мы можем сделать это следующим образом.

Во-первых, T неотрицательно для всех n, поэтому, в частности, T(n/2) >= 0, поэтому для всех n имеем неравенство

T(n) >= 4T(n-3)

Теперь мы хотим использовать это неравенство для сравнения T(n-3) и T(n/2). Применяя эту частоту n/6 - 1 раз, получим, что

T(n-3) >= 4^{n/6 - 1} * T(n/2)

(Потому что (n/6 - 1) * 3 = n/2 - 3 и n/2 - 3 + n/2 = n - 3).

Отсюда следует, что T(n/2) мало по сравнению с T(n-3):

T(n/2) <= 4^{-n/6 + 1} * T(n-3)

Теперь для любого epsilon > 0 существует n_0 такое, что для n > n_0, 4^{-n/6 + 1} < epsilon. (Потому что предел 4^{-n/6 + 1} равен нулю, так как n становится большим.)

Это означает, что для любого epsilon > 0 достаточно велико n, так что

4T(n-3) <= T(n) <= (4 + epsilon) T(n-3)

Это дает плотную оценку T(n) = 4^(n/3 + o(n)).


Получение более четкой оценки

В комментариях о том, как избавиться от o(n) выше, есть вопрос, чтобы получить еще более четкую оценку.

Я боюсь, что это в основном просто собирается стать педантичным - обычно никто не заботится о терминах низкого порядка, а гвозди их точно - это всего лишь исчисление. Но мы можем сделать еще немного сегодня.

Какая разница

Прежде всего, в чем разница между O(4^{n/3}) и 4^{n/3 + o(n)}? (В качестве альтернативы мы могли бы записать последнее как (4+o(1))^{n/3}.)

Разница заключается в том, насколько сильно они контролируют члены низкого порядка. O(4^{n/3}) контролирует их очень сильно - он говорит, что вы не превышаете (конкретное) значение 4^{n/3}) более чем постоянным фактором.

4^{n/3 + o(n)}, позволяет превышать 4^{n/3} более чем на постоянный коэффициент. Но этот фактор субэкспоненциальен в n, он пренебрежимо мал по сравнению с 4^{n/3}.

Например, рассмотрим функцию f(n) = n * 4^{n/3}. Эта функция не O(4^{n/3}). В самом деле, он превосходит его в факторе n, больше, чем постоянный фактор.

Однако f(n) находится в классе 4^{n/3 + o(n)}. Зачем? Потому что n = O(4^{epsilon n}) для каждого epsilon > 0.

Если у вас есть такое неравенство,

4T(n-3) <= T(n) <= (4 + epsilon) T(n-3)

для каждого epsilon > 0, вы можете только вывести из этого T(n) = (4 + o(1))^{n/3}.

Чтобы получить более четкую привязку, нам нужно рассматривать epsilon как функцию от n, а не как константу (как, например, в более ленивой версии).

Proof

Пусть epsilon(n) = 4^{-n/6 + 1} в дальнейшем. Тогда мы уже показали

T(n) <= (4 + epsilon(n)) T(n-3)

и мы хотим видеть T = O(4^{n/3}).

Это можно развернуть как итерированный продукт:

T(n) = PI_{i=1}^{n/3} (4 + epsilon(3i))

Мы можем рассчитать каждый член и вывести коэффициент 4, чтобы получить

T(n) = 4^{n/3} * PI_{i=1}^{n/3} (1 + epsilon(3i)/4 )

Цель состоит в том, чтобы показать, что

PI_{i=1}^{n/3} (1 + epsilon(3i)/4 ) = O(1)

а затем мы закончим.

Для этого возьмем журнал и покажем, что это O(1).

SUM_{i=1}^{n/3} log(1 + epsilon(3i/4))

Мы связали это, используя log(1+x) <= x для x >= 0.

SUM_{i=1}^{n/3} epsilon(3i/4)

Теперь мы используем определение epsilon. На самом деле нам нужно знать epsilon(n) <= C^{-n} для некоторого C > 1. Вышеизложенное становится

SUM_{i=1}^{n/3} C'^{-i}

для некоторой константы C' > 1. Но это геометрический ряд, поэтому он ограничен сверху бесконечным геометрическим рядом при

1 / (1 - 1/C') = O(1)

Таким образом, T(n) = O(4^{n/3}). Поскольку у нас уже было T(n) = Omega(4^{n/3}), мы теперь имеем его с точностью до констант, T(n) = Θ(4^{n/3})

Вы можете решить для себя, если эта дополнительная работа сделала вещи более ясными: p Лично я предпочитаю оставить o(n) там обычно.

Ответ 3

IMO, временная сложность Θ(r^n), где r=³√4.

Действительно, включив это выражение в рекуррентное соотношение,

r^n = 1 + 4 r^n / r³ + 4 r^(n/2) = 1 + r^n + 4 √(r^n),

где второй член доминирует асимптотически.

Вот график точного количества вызовов на foo, разделенных на r^n для удобства чтения. Мы приняли слово [n/2] в f(n/2).

Отношение имеет тенденцию к повторяющейся последовательности 46.6922952502, 63.4656065932 74.1193985991. Кажется, это подтверждает Θ(r^n).

введите описание изображения здесь

Обновление

По индукции мы можем показать, что при n >= 21,

T(n) < B(n) = 75.(s^(2n) - 4.s^n),

с s=³√2.

Действительно, по рекуррентному уравнению и предположению индукции

T(n+3) = 1 + 4.T(n) + 4.T([(n+3)/2])
       < 1 + 4.75.(s^(2n) - 4.s^n) + 4.75.(s^(2[(n+3)/2])) - 4.s^[(n+3)/2])

Сравним это с оценкой B(n+3), чтобы установить

1 + 4.75.(s^(2n) - 4.s^n) + 4.75.(s^(2[(n+3)/2])) - 4.s^[(n+3)/2])
     < 75.(s^(2n+6) - 4.s^[(n+3)/2]

Мы можем упростить члены 4.75.s^(2n) и делить на 300.s^n:

s^(-n)/300 - 4 + s^(-(n+3)%2) - 4.s^([(n+3)/2]-n) < - s^([(n+3)/2]-n)

или

s^(-n)/300 + s^(-(n+3)%2) < 4 + 5.s^([(n+3)/2]-n).

Это неравенство верно для любого n, так что T(n) < B(n) => T(n+3) < B(n+3).

Теперь для базового случая мы используем таблицу T(n), заданную @CommuSoft (и проверяем независимо) и проверяем численно

T(21) = 744009 < 75.(s^42 - 4.s^21) = 1190400
T(22) = 1622601 < 75.(s^44 - 4.s^22) = 1902217.444...
T(23) = 3015241 < 75.(s^46 - 4.s^23) = 3035425.772...
...
T(41) = 12530692681 < 75.(s^82 - 4.s^41) = 12678879361

Это показывает, что шаг индукции может быть применен от n=39 и далее ([(39+3)/2]=21).

Тогда

T(n) = O(75.(s^(2n) - 4.s^n)) = O(r^n).

(На самом деле, для всех n >= 23, 46.r^n < T(n) < 75.r^n и это очень плотно, T(n) = Θ(r^n).)