Big-O算法分析

发布于 2025-01-06 21:14:34 字数 2019 浏览 4 评论 0原文

我想说这不是家庭作业的问题。它只是 USACO 网站上学习动态规划概念的在线教程资源。 在资源中,给出了一个问题如下。

问题: 一个多达 10000 个整数的序列,( 0 < 整数 < 100,000),最大递减子序列是多少?

伙计们,给出了体面的递归方法

 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下运行时间还是可以接受的。肯定有问题。请帮我。谢谢。

在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  }

I would say it's not a homework problem. It's just a tutorial resource online to learn the dynamic programming concepts from USACO website.
In the resource, a problem was given as follows.

Question:
A sequcen of as many as 10000 integers, ( 0 < integer < 100,000), what is the maximum decreasing subsequence?

The decent recursive approach was given

 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  }

Guys, I am not good at the algorithmic analysis. Would you please tell me what's the Big-O notation to this recursive enumeration solution in worst case as tight as possible. My personal thought would be O(N^N), but I have no confidence. Because the runtime is still acceptable under N <= 100. There must be something wrong. Please help me. Thank you.

In the USACO website, it gives the dynamic programming approach in O(n^2) as follows.

 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  }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

神经暖 2025-01-13 21:14:34

只要看看你调用该函数时使用了什么样的参数即可。第一个决定第三个(顺便说一句,这意味着您需要第三个参数)。第一个范围介于 0 和 n 之间。第二个比第一个小。这意味着您最多对该函数有 n^2 次不同的调用。

现在的问题是您使用相同的参数调用该函数多少次。答案很简单:您实际上生成了每个递减子序列。这意味着对于序列 N、N-1、N-2...,您将生成 2^N 个序列。很差,对吧(如果你想尝试我给你的序列)?

但是,如果您使用您应该已经阅读过的记忆技术,您可以将复杂度提高到 N^3(每次调用该函数时最多执行 n 次操作,不同的调用是 N^2 并且记忆允许您只支付一次对于不同的呼叫)。

Just look at with what kind of parameters you call the function. The first determines the third (which btw means you needed have the third parameter). The first ranges between 0 and n. The second one is smaller than the first. This means that you have at most n^2 different calls to the function.

Now comes the question how many times you call the function with the same parameters. And the answer is simple: you actually generate every single decreasing subsequece. This means that for the sequence N, N-1, N-2, ... you will generate 2^N sequences. Pretty poor, right (if you want experiment with the sequence I have given you)?

However if you use the memoization technique you should have already read about, you can improve the complexity to N^3 (at most n operations in every call to the function, the different calls are N^2 and memoization allows you to pay only once for a different call).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文