Big-O алгоритмический анализ - PullRequest
2 голосов
/ 17 февраля 2012

Я бы сказал, что это не домашнее задание. Это просто учебный онлайн-ресурс для изучения концепций динамического программирования на веб-сайте USACO. На ресурсе проблема была сформулирована следующим образом.

Вопрос: Последовательность из 10000 целых чисел (0 <целое число <100 000), какова максимальная убывающая подпоследовательность? </p>

Был дан достойный рекурсивный подход

 1 #include <stdio.h>      
 2  long n, sequence[10000];
 3  main () {
 4       FILE *in, *out;                     
 5       int i;                             
 6       in = fopen ("input.txt", "r");     
 7       out = fopen ("output.txt", "w");   
 8       fscanf(in, "%ld", &n);             
 9       for (i = 0; i < n; i++) fscanf(in, "%ld", &sequence[i]);
10       fprintf (out, "%d\n", check (0, 0, 99999));
11       exit (0);
12  }


13  check (start, nmatches, smallest) {
14      int better, i, best=nmatches;
15      for (i = start; i < n; i++) {
16          if (sequence[i] < smallest) {
17              better = check (i, nmatches+1, sequence[i]);
18              if (better > best) best = better;
19          }
20      }
21      return best;
22  }

Ребята, я не силен в алгоритмическом анализе. Не могли бы вы сказать мне, что такое обозначение Big-O для этого решения с рекурсивным перечислением в худшем случае, насколько это возможно. Моя личная мысль была бы O (N ^ N), но я не уверен. Поскольку время выполнения все еще допустимо при N <= 100. Должно быть, что-то не так. Пожалуйста, помогите мне. Спасибо. </p>

На веб-сайте USACO он дает подход динамического программирования в O (n ^ 2) следующим образом.

 1  #include <stdio.h>
 2  #define MAXN 10000
 3  main () {
 4      long num[MAXN], bestsofar[MAXN];
 5      FILE *in, *out;
 6      long n, i, j, longest = 0;
 7      in = fopen ("input.txt", "r");
 8      out = fopen ("output.txt", "w");
 9      fscanf(in, "%ld", &n);
10      for (i = 0; i < n; i++) fscanf(in, "%ld", &num[i]);
11      bestsofar[n-1] = 1;
12      for (i = n-1-1; i >= 0; i--) {
13          bestsofar[i] = 1;
14          for (j = i+1; j < n; j++) {
15              if (num[j] < num[i] && bestsofar[j] >= bestsofar[i])  {
16                  bestsofar[i] = bestsofar[j] + 1;
17                  if (bestsofar[i] > longest) longest = bestsofar[i];
18              }
19          }
20      }
21      fprintf(out, "bestsofar is %d\n", longest);
22      exit(0);
23  }

1 Ответ

3 голосов
/ 17 февраля 2012

Просто посмотрите, с какими параметрами вы вызываете функцию. Первый определяет третий (что, кстати, означает, что вам нужен третий параметр). Первый диапазон от 0 до n. Второй меньше первого. Это означает, что у вас есть не более n ^ 2 различных вызовов функции.

Теперь возникает вопрос, сколько раз вы вызываете функцию с одинаковыми параметрами. И ответ прост: вы на самом деле генерируете каждую убывающую последующую подпоследовательность. Это означает, что для последовательности N, N-1, N-2, ... вы сгенерируете 2 ^ N последовательностей. Довольно бедно, верно (если вы хотите поэкспериментировать с последовательностью, которую я вам дал)?

Однако если вы используете технику запоминания, о которой вы уже должны были прочитать, вы можете повысить сложность до N ^ 3 (не более n операций при каждом вызове функции, различные вызовы - это N ^ 2, а запоминание позволяет платить только один раз за другой звонок).

...