【问题标题】:Finding vampire numbers from 10 to 1 million寻找从 10 到 100 万的吸血鬼数量
【发布时间】:2014-02-05 16:20:56
【问题描述】:

我是一名新的 C 学习者,并试图找到从 10 到 100 万的吸血鬼数字。

吸血鬼号: http://en.wikipedia.org/wiki/Vampire_number

代码已经准备好了,但是它并没有像预期的那样工作。它只是继续搜索很长时间而不打印任何东西,然后打印出大量的数字。我无法弄清楚问题是什么,这就是代码的样子:

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

#define true 1
#define false 0

int main(void){
   int i,j,t,s,m,n,counter=0;

   for(i=10; i<100; i++){
      m = Control2Digits(i);
      if(m == true){
         counter++;
         printf("%d.Vampire number: %d \n", counter, i);
      }
   }

   for(j=1000; j<10000; j++){
     m = Control4Digits(j);
     if(m == true){
         counter++;
         printf("%d.Vampire number: %d \n", counter , j);
      }
   }

   for(t=100000; t<1000000; t++){
      for(s=100000; s<1000000; s++){
         m = Control6Digits(s,t);
         if(m == true){
            n = (s*t);
            counter++;
            printf("%d.Vampire number: %d \n", counter, n);
         }
      }
   }
}

int Control2Digits(int number){
   int n1,n2;

   n1 = number%10;
   n2 = (number-n1)/10;

   if(n1*n2 == number)
      return true;

   return false;

}

int calculate4(int s1, int s2, int s3, int s4){
   int p1,p2;
   p1 = (s1*10)*s2;
   p2 = (s3*10)*s4;
   return (p1*p2);
}

int Control4Digits(int number){

   int g1,g2;
   int t1,t2,t3,t4;

   if(number%100 == 0)
      return false;

   g1 = number/100;
   g2 = number%100;
   t1 = g1/10;
   t2 = g1%10;
   t3 = g2/10;
   t4 = g2%10;

   if(calculate4(t1,t2,t3,t4) == number)
      return true;
   else if(calculate4(t2,t1,t3,t4) == number)
      return true;
   else if(calculate4(t2,t1,t4,t3) == number)
      return true;
   else if(calculate4(t1,t2,t4,t3) == number)
      return true;
   else if(calculate4(t1,t3,t2,t4) == number)
      return true;
   else if(calculate4(t3,t1,t2,t4) == number)
      return true;
   else if(calculate4(t1,t4,t2,t3) == number)
      return true;
   else if(calculate4(t1,t3,t4,t2) == number)
      return true;
   else if(calculate4(t4,t1,t2,t3) == number)
      return true;
   else if(calculate4(t3,t1,t4,t2) == number)
      return true;
   else if(calculate4(t1,t4,t3,t2) == number)
      return true;
   else if(calculate4(t4,t1,t3,t2) == number)
      return true;

   return false;

}

int Control6Digits(int num1, int num2){
   long int k,l,m,n,c;
   k = num1%10;
   l = num2%10;

   if(k + l == 0)
      return false;
   else{
      m = (num1*num2);
      n = (num1*1000+num2);

      if(a == g)
         return true;
      c = true;
   }

   return false;
}

【问题讨论】:

  • 不要使用@barakmanos 的建议来修复您的代码,因为这会使事情变得不清楚。
  • 没有意识到这是一个糟糕的建议。如果您能详细说明,那么我也许可以修复它(或决定将其删除)...

标签: c loops infinite-loop nested-loops


【解决方案1】:

Beer Baron 已经指出了你对四位数吸血鬼数字的错误。

您的六位数字的逻辑没有正确实现,也不清楚。 (在发布状态下,它不会编译:a 是什么,g 是什么?)如果您按照四位数代码的逻辑,您必须检查每个数字的 360 种组合,这有点多。

另外,我希望您对您的代码执行这么长时间不会感到惊讶:您有两个嵌套循环,从 100,000 到 100 万,即每个循环 900,000。那是 8100 亿次迭代。

您的四位数代码原则上有效,如果您想检查单个数字是否有吸血鬼,则可以。如果要识别某个范围内的所有吸血鬼数字,则应使用“扩展”方法:不要将 v = a * b 从 1,000 迭代到 10,000,而是尝试将 ab 从 10 到 100 的两个嵌套循环。 (b 不必每次都从 10 开始。例如,如果 a 是 20,则从 50 开始就足够了,因为任何较低 b 的产品将具有更少的数字。)

(这个方法有点像使用 Erathostenes 的筛子来寻找素数。它不一样,因为你仍然需要测试你的嫌疑人。这个解决方案的一个缺点是你不会找到你的吸血鬼数字升序排序。例如,您会在1260 == 21 * 60 之前找到1395 == 15 * 93。如果您的数字必须排序,请将它们存储在数组中并在打印前对其进行排序。)

您现在必须想出一种有效的方法来比较数字。一个简单的解决方案是为每个数字设置一个带有计数器的数组。从所有计数器都为零开始,加上可疑吸血鬼数字的数字,减去尖牙的数字,如果你再次全为零,你就找到了一个吸血鬼数字。

另一种解决方案是将所谓的吸血鬼编号打印到一个字符串,两个尖牙打印到另一个字符串,按字符对字符串进行排序并进行比较。

您可能还可以使用位掩码,但由于数字的计数也必须匹配,因此为某些数字设置位是不够的。对于高达一百万的数字,您可以添加 8 的幂,例如数字 3 的 8^3。

我喜欢的一种方法是使用素数的乘积来识别数字。您必须注意整数溢出,但对于高达一百万的数字,您是安全的:

typedef unsigned int uint;

uint fact(uint a)
{
    static uint primes[10] = {2, 3, 5, 7, 11, 13, 17, 23, 29, 31};
    uint r = 1u;

    while (a) {
        r *= primes[a % 10];
        a /= 10;
    }

    return r;
}

然后你可以像这样测试尖牙和数字:

v = a * b;
if (fact(a) * fact(b) == fact(v)) printf("%u\n", v);

【讨论】:

  • 我认为:for(i=100; i&lt;1000; i++){ for(j=i; j&lt;1000; j++){ m = i*j; } } 那个嵌套循环给了我所有 6 位数字,它们是通过将两个 3 位数字相乘得到的。但是,问题是我想不出一个关于如何找出其中一个是否是吸血鬼号码的好主意。
  • 另外,我将所有数字分隔为一个数字以获得吸血鬼数字。但是,这是我来的最后一点。
  • @Sixie:嗯,没有必要分开任何东西。你已经有了ij 和procuct m 的因子,你只需要检查1000 * i + jm 中的数字是否相同。下限可以是j = max(100 * 1000 / i, i)
  • for(i=100; i&lt;1000; i++){ for(j=i; j&lt;1000; j++){ m = i*j; n = (1000*i)+j; p = (1000*j)+i; if(m==n || m==p) printf("%d", m); } } 如果我理解正确的话。还是有问题。
  • @Sixie:不,你没有正确理解。我说你必须检查数字是否相同。您只是在检查两种可能性。 (更糟糕的是:您正在检查两种不可能的情况。想想当x 小于1000x*i 不能等于1000*i1000*i + j。)在我上面的帖子中,我有概述了检查数字的各种方法,我什至提供了其中一种的代码。
【解决方案2】:

变化:

p2 = (s3*10)*s3;

收件人:

p2 = (s3*10)*s4;

还有一条小建议:在代码中的所有位置将 intlong 更改为 unsigned long long,以防止大型输入的计算溢出。

【讨论】:

  • 完成。但是,运行时没有变化。
【解决方案3】:
int calculate4(int s1, int s2, int s3, int s4) {
   int p1,p2;
   p1 = (s1*10)+s2;
   p2 = (s3*10)+s4;
   return (p1*p2);
}

你正在用 * 而不是 + 重建这两个部分

然后你得到例如

    1.Vampire number: 1260
    2.Vampire number: 1395
    3.Vampire number: 1435
    4.Vampire number: 1530
    5.Vampire number: 1827
    6.Vampire number: 2187
    7.Vampire number: 6880

【讨论】:

  • 它仍然不打印超过 100k 的数字。
猜你喜欢
  • 2013-06-25
  • 2016-08-02
  • 2020-08-14
  • 1970-01-01
  • 2016-05-27
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 1970-01-01
相关资源
最近更新 更多