2015-02-23 129 views
2

我需要在C中设计一个算法来计算0到1,000,000的数字的唯一组合。例如,当13出现时,31将不会被包含在这个序列中。任何人都可以帮我找到一个算法来描述这个?该系列中的前几位数字为:C中数字的唯一组合

1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,22,23,24,25,26,27,28,29,33,etc 

谢谢!

编辑 - 对不起,忘了提,零不包括在从0系列

+0

在本系列的前几个数字是,0,1,2,3,4,5,6,7,8 ,9,11,12,13,14,15,16,17,18,19,22,23,24等。 – Bucknall 2015-02-23 21:09:23

+0

你想要实际的数字还是只是它们的数量?这是完全不同的问题 – amit 2015-02-23 21:17:16

+3

你应该解释为什么10没有出现在列表中。 – user3386109 2015-02-23 21:21:59

回答

6
#include <stdio.h> 
int main(void) { 
    int i, n; 
    for (n = 1; n < 1000000; n++) { 
     for (i = n;;) { 
      if (i/10 % 10 > i % 10) break; 
      if ((i /= 10) == 0) { printf("%d\n", n); break; } 
     } 
    } 
} 

5004号1000000

一个快得多的版本:

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

static long long enumerate(char *p, int i, int n, int digit, int silent) { 
    long long count = 0; 
    if (i >= n) { 
     if (!silent) printf("%s\n", p); 
     return 1; 
    } 
    for (p[i] = digit; p[i] <= '9'; p[i]++) 
     count += enumerate(p, i + 1, n, p[i], silent); 
    return count; 
} 

int main(int argc, char **argv) { 
    char array[256]; 
    int i, n; 
    int max = (argc > 1) ? strtol(argv[1], NULL, 0) : 6; 
    int silent = 0; 
    long long count = 0; 
    if (max < 0) { 
     max = -max; 
     silent = 1; 
    } 
    array[sizeof(array)-1] = '\0'; 
    for (n = 1; n <= max; n++) { 
     count += enumerate(array + sizeof(array) - 1 - n, 0, n, '1', silent); 
     if (silent) 
      printf("%lld combinations between 0 and 1E%d\n", count, n); 
    } 
} 

调用用一个正数来枚举组合和一个负数来对它们进行计数。

+0

这段代码是如何工作的? – immibis 2015-02-23 21:37:34

+0

只有低于10亿的'24309'组合达到1亿和'48619'。系列长度似乎像log(N)一样增长。找到N = 10^n的分析公式是你的新任务! – chqrlie 2015-02-23 21:44:56

+0

我知道我应该完成你的功课,我无法抗拒。我测试1和上限之间的每个数字。我检查最后一位数字是否至少与前一位数字一样大,并且通过将数字除以10直到它为0再次执行。如果测试结果为0,则数字为OK并且被打印。 – chqrlie 2015-02-23 21:47:48

2

函数next将数组a更新为下一个数字,并返回底部数字的值。 main函数遍历序列,一旦顶端数字为10就停止(因为一旦阵列用完,next只是不断递增最高有效位)。

该算法在单词中忽略边界检查可以被描述为“找到下一个数字,向底部数字加1,如果溢出找到下一个数字忽略底部数字,然后复制新的底部数字“。

#include <stdio.h> 

int next(int *a, size_t len) { 
    if (*a == 9 && len > 1) { 
     *a = next(a-1, len-1); 
    } else { 
     *a += 1; 
    } 
    return *a; 
} 

#define N 6 

int main(int argc, char *argv[]) { 
    int a[N] = {0}; 
    while (next(a+N-1, N) != 10) { 
     for (int i = 0; i < N; i++) { 
      if (a[i] != 0) printf("%d", a[i]); 
     } 
     printf("\n"); 
    } 
    return 0; 
} 

您可以计算O(N)时间(其中N是位数)的解。如果K(n,d)是正好具有n位数的解,并且其最高位是9-d,那么K(0,d)= 1,并且K(n + 1,d)= K(n, 0)+ K(n,1)+ ... + K(n,d)。具有n个或更少位数的解的数目为K(1,8)+ K(2,8)+ ... + K(n,8)。这些意见得到这个动态规划的解决方案:

int count(int n) { 
    int r[9] = {1}; 
    int t = 0; 
    for (int i = 0; i < n+1; i++) { 
     for (int j = 1; j < 9; j++) { 
      r[j] += r[j-1]; 
     } 
     t += r[8]; 
    } 
    return t - 1; 
} 

int main(int argc, char* argv[]) { 
    printf("there are %d numbers.\n", count(6)); 
    return 0; 
} 

给出:

there are 5004 numbers. 
+0

挺飘逸! '1和1 googol之间的'4263421511270'组合。我不得不在'count'中使用'unsigned long long',但它非常快。你统治! – chqrlie 2015-02-24 19:47:41