【问题标题】:Change enumerate algorithm to show greater ranges first更改枚举算法以首先显示更大的范围
【发布时间】:2016-05-03 16:00:10
【问题描述】:

我有一个需要枚举算法的程序,我让它以这种方式工作:

#include <stdio.h>

void show (int subs[], int k) {
    int i;
    for (i=1; i<=k; i++)
        printf("%i ", subs[i]);
    puts("");
}

void enumerate (int n) {
    int subs[n+1], k = 0;
    *subs = 0;
    while (1) {
       if (subs[k] < n) {
            subs[k+1] = subs[k] + 1;
            k++;
        } else {
            subs[k-1] += 1;
            k--;
        }
        if (k == 0) break;
        show (subs, k);
    }
}

int main(void) {
    enumerate(4);
    return 0;
}

ideone

它应该是 O(2N) 次调用show(subs, k)。最初,我认为这不会有问题,但我错了。实际上我的程序需要:

2 secs for n=25
4 secs for n=26
9 secs for n=27
18 secs for n=28
...

如您所见,它的时间增长得非常快。我的程序也做了一个快速排序,而不是show,它用我的逻辑调用了另一个函数,不过这里没关系。

但由于我必须做得更快,我开始分析我的问题......

我说过,如果在序列1 2 4 5(范围长度为 4)中找到我想要的解决方案,那么所有范围长度低于该值的序列对我的逻辑来说都是毫无价值的。

然后,我尝试对上面显示的enumerate 函数进行编码,使具有更大范围的序列首先出现,因为如果我得到这个,我可以在找到所需值时简单地破坏枚举函数。

但经过大约两个小时的挣扎后,我发现自己有 4 个内循环 (!!) 和错误的序列。

请各位忍者帮我解决这个问题?提前致谢。

更新

如果你运行enumerate(3),你会得到:

1 
1 2 
1 2 3 
1 3 
2 
2 3 
3

我想要的是首先更大的范围长度,所以:

1 2 3 
1 2 
1 3 
2 3 
1 
2 
3

【问题讨论】:

  • 我看到一些没有明确目的的随机代码。您的计划的实际目标是什么?
  • @btilly。我试图只显示代码的相关部分。或者你的意思是一个明确的例子?我会更新一个
  • 所以你只想要最后一个块? (即)您有1 2 3不需要 需要其他3 序列,例如3 2 12 3 11 3 2?而且,您不需要2 1?如果是这样,对上面的算法有一个轻微的扩展,可以在不需要排序的情况下按顺序给它们[更大范围优先]。我以前不得不做这种事情,但我有不同的输出要求,所以我只是想在提供答案之前了解你的。
  • @CraigEstey。我的程序读取x 间隔(开始和结束时间为整数),并返回最大不相交间隔x 值已给出。对不起,我的英文术语,我不知道它们是否正确

标签: c algorithm logic


【解决方案1】:

首先,您的输出大小会增长为2<sup>n</sup>,而不是n<sup>2</sup>。因此你的性能问题。重新排序可能会有所帮助,但重新考虑您的算法可能会有所帮助。

话虽如此,这里有一个解决方案:

#include <stdio.h>

void show (int subs[], int k) {
    int i;
    for (i=1; i<=k; i++)
        printf("%i ", subs[i]);
    puts("");
}

void enumerate (int n) {
    int subs[n+1], k = n, l = 0;
    *subs = 0;
    // Populate subs with longest possible sequence.
    for (int i = 0; i < n + 1; i++) {
       subs[i] = i;
    }
    while (0 < k) {
       show(subs, k);
       // Find first increasible spot 
       l = 0;
       for (int i = k; 0 < i; i--) {
          if (subs[i] + k - i < n) {
             l = i;
             break;
          }
       }
       if (0 < l) {
          // Create our increasing sequence
          subs[l]++;
          for (int i = l+1; i <= n; i++) {
             subs[i] = subs[i-1] + 1;
          }
       }
       else {
          // Make k shorter and reset the sequence.
          k = k-1;
          for (int i = 0; i < n + 1; i++) {
             subs[i] = i;
          }
       }
    }
}

int main(void) {
    enumerate(4);
    return 0;
}

【讨论】:

  • 这太棒了+1!到目前为止,我一直在尝试这样做五个小时。我现在就尝试一下,看看结果。另外,我不知道我为什么写 n^2,我的意思是 2^n.. 也谢谢你
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-06
  • 1970-01-01
相关资源
最近更新 更多