3n + 1在线评审程序

时间:2013-12-19 23:28:59

标签: c

我编写了一个程序来解决在线评判中的3n + 1问题(Collatz Conjecture)。我注意到了重要的问题,例如,第一个输入可能小于第二个输入,等等。

但在网上判断时,我总会得到错误答案的通知。你能帮我看看我犯错的地方吗?谢谢。

以下是我的计划。请注意,我使用数组来存储遍历数字的循环。

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>


int main(int argc, char const *argv[])
{
    int maxcyc = 0;
    int curcyc;
    int i, min, max;
    unsigned long n;
    int *cach = (int *)malloc(1000000 * sizeof(int));
    if (cach == NULL)
    {
        printf("Memory Allocation Error\n");
    }
    for (i = 0; i < 1000000; ++i)
    {
        cach[i] = 0;
    }
    if (scanf("%d  %d", &min, &max) == 2)
    {
        printf("%d %d ", min, max);
        if (min > max)
        {
            min = min ^ max;
            max = max ^ min;
            min = min ^ max;
        }
        for (i = min; i < max + 1; ++i)
        {
            curcyc = 1;
            n = i;
            while (n != 1)
            {
                if (n < 1000000 && cach[n])
                {
                    curcyc = curcyc + cach[n] - 1;
                    break;
                }
                curcyc++;
                if (n & 0x0001)
                {
                    if (n >= ULONG_MAX / 3)
                    {
                        printf("%d overflow at step %d\n", i, curcyc);
                    }
                    n = 3 * n + 1;
                }
                else
                {
                    n = n >> 1;
                }
            }
            cach[i] = curcyc;
            maxcyc = maxcyc > curcyc ? maxcyc : curcyc;
        }
        printf("%d\n", maxcyc);
    }
    free(cach);
    return 0;
}

PS:有关此问题的详细说明和说明,请参阅http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=3&page=show_problem&problem=36

我已经通过将n的类型更改为unsigned long来更新代码,并添加了if语句以预期检查溢出超前3 * n + 1.但是此程序中仍然存在错误,没有通过判决。还需要帮助。感谢。

2 个答案:

答案 0 :(得分:1)

将curcyc从0开始而不是1,并且不从缓存值中减去。因此,你的算法是错误的。

此外,在执行算法期间,n可能会溢出,具体取决于起始值。

答案 1 :(得分:1)

我对此工作有点自信。它产生的答案与我在高达100万的评论中提到的蛮力bc程序相同(至少,一旦我修改了bc程序来计算链中的值的数量,比过渡的数量)。它快达100万。当缓存在1000万和1亿时变得不那么有效时,它会变慢。

示例输出(使用-DPRODUCTION编译的代码):

$ j=10; for i in 0 0 0 0 0 0 0; do j="$j$i"; ./collatz-so <<< "2 $j"; done
2 100 119
2 1000 179
2 10000 262
2 100000 351
2 1000000 525
2 10000000 686
2 100000000 950
$

示例输出,其代码已编译为debug:

$ ./collatz-so <<< '1 30'
   1:    1
   2:    2
   3:    8
   4:    3
   5:    6
   6:    9
   7:   17
   8:    4
   9:   20
  10:    7
  11:   15
  12:   10
  13:   10
  14:   18
  15:   18
  16:    5
  17:   13
  18:   21
  19:   21
  20:    8
  21:    8
  22:   16
  23:   16
  24:   11
  25:   24
  26:   11
  27:  112
  28:   19
  29:   19
  30:   19
1 30 112
$

代码:

#include <stdio.h>
#include <stdlib.h>

#if defined(PRODUCTION)
#define DEBUG 0
#else
#define DEBUG 1
#endif

static const int debug = DEBUG;

enum { CACHE_SIZE = 1000000 };

int main(void)
{
  int maxcyc = 0;
  int curcyc;
  int i, min, max;
  unsigned long n;
  int *cache = (int *)calloc(CACHE_SIZE, sizeof(int));
  if (cache == NULL)
  {
    printf("Memory Allocation Error\n");
    return 1;
  }

  if (scanf("%d %d", &min, &max) == 2)
  {
    if (min > max)
    {
      min = min ^ max;
      max = max ^ min;
      min = min ^ max;
    }
    for (i = min; i < max + 1; ++i)
    {
      curcyc = 1;
      n = i;
      while (n != 1)
      {
        if (n < CACHE_SIZE && cache[n])
        {
          //printf("%lu: cache[%lu] = %d; c = %d\n", n, n, cache[n], curcyc);
          curcyc += cache[n] - 1;
          break;
        }
        curcyc++;
        if (n & 0x0001)
          n = 3 * n + 1;
        else
          n /= 2;
      }
      if (i < CACHE_SIZE)
      {
        cache[i] = curcyc;
        //printf("cache[%d] = %d\n", i, curcyc);
      }
      if (debug)
        printf("%4d: %4d\n", i, curcyc);
      maxcyc = maxcyc > curcyc ? maxcyc : curcyc;
    }
    printf("%d %d %d\n", min, max, maxcyc);
  }

  free(cache);
  return 0;
}