Наименьшее число, которое равномерно делится на все числа от 1 до 20? - PullRequest
8 голосов
/ 24 января 2010

Я сделал эту проблему [ Project Euler, проблема 5 ], но очень плохой способ программирования, см. Код на c ++,

#include<iostream>
using namespace std;
// to find lowest divisble number till 20

int main()
{
int num = 20, flag = 0;

while(flag == 0)
{
    if ((num%2) == 0 && (num%3) == 0 && (num%4) == 0    && (num%5) == 0 && (num%6) == 0 
    && (num%7) == 0 && (num%8) == 0 && (num%9) == 0 && (num%10) == 0 && (num%11) == 0 && (num%12) ==0   
    && (num%13) == 0 && (num%14) == 0 && (num%15) == 0 && (num%16) == 0 && (num%17) == 0 && (num%18)==0
    && (num%19) == 0    && (num%20) == 0)       

    {
        flag =  1;
        cout<< " lowest divisible number upto 20 is  "<< num<<endl;
    }

    num++;
}

}

Я решал это в C ++ и застрял в цикле, как бы решить этот шаг ......

  • рассмотрим число = 20 и разделим его на числа от 1 до 20
  • проверить, все ли остатки равны нулю,
  • Если да, выйдите и покажите номер выхода
  • или иначе num ++

Я не знаю, как использовать управляющие структуры, поэтому сделал этот шаг

if ((num%2) == 0 && (num%3) == 0 && (num%4) == 0    && (num%5) == 0 && (num%6) == 0 
&& (num%7) == 0 && (num%8) == 0 && (num%9) == 0 && (num%10) == 0 && (num%11) == 0 && (num%12) ==0   
&& (num%13) == 0 && (num%14) == 0 && (num%15) == 0 && (num%16) == 0 && (num%17) == 0 && (num%18)==0
&& (num%19) == 0    && (num%20) == 0) `

как правильно это закодировать?

ответ на эту проблему:

abhilash@abhilash:~$ ./a.out 
 lowest divisible number upto 20 is  232792560

Ответы [ 12 ]

19 голосов
/ 24 января 2010

Наименьшее число, которое делится на два числа, является LCM из этих двух чисел. На самом деле, наименьшее число, делимое на набор из N чисел x1..xN, является LCM этих чисел. Легко вычислить LCM из двух чисел (см. Статью в Википедии), и вы можете расширить до N чисел, используя тот факт, что

LCM(x0,x1,x2) = LCM(x0,LCM(x1,x2))

Примечание. Остерегайтесь переполнения.

Код (на Python):

def gcd(a,b):
    return gcd(b,a%b) if b else a

def lcm(a,b):
    return a/gcd(a,b)*b

print reduce(lcm,range(2,21))
15 голосов
/ 24 января 2010

Факторизация всех целых чисел от 1 до 20 в их простые разложения. Например, коэффициент 18 равен 18 = 3 ^ 2 * 2. Теперь для каждого простого числа p, которое появляется в простой факторизации некоторого целого числа в диапазоне от 1 до 20, найдите максимальный показатель, который он имеет среди всех этих простых факторизации. Например, простое 3 будет иметь показатель степени 2, потому что оно появляется при факторизации 18 как 3 ^ 2, и если оно появилось в любой простой факторизации с показателем 3 (то есть 3 ^ 3), это число будет должно быть не менее 3 ^ 3 = 27, что выходит за пределы диапазона от 1 до 20. Теперь соберите все эти простые числа с соответствующими им показателями, и у вас есть ответ.

Итак, в качестве примера, давайте найдем наименьшее число, равномерно делимое на все числа от 1 до 4.

2 = 2^1
3 = 3^1
4 = 2^2

Появляются простые числа 2 и 3. Отметим, что максимальный показатель 2 равен 2, а максимальный показатель 3 равен 1. Таким образом, наименьшее число, которое равномерно делится на все числа от 1 до 4, равно 2 ^ 2 * 3 = 12.

Вот относительно простая реализация.

#include <iostream>
#include <vector>

std::vector<int> GetPrimes(int);
std::vector<int> Factor(int, const std::vector<int> &);

int main() {
    int n;
    std::cout << "Enter an integer: ";
    std::cin >> n;
    std::vector<int> primes = GetPrimes(n);
    std::vector<int> exponents(primes.size(), 0);

    for(int i = 2; i <= n; i++) {
        std::vector<int> factors = Factor(i, primes);
        for(int i = 0; i < exponents.size(); i++) {
            if(factors[i] > exponents[i]) exponents[i] = factors[i];
        }
    }

    int p = 1;
    for(int i = 0; i < primes.size(); i++) {
            for(int j = 0; j < exponents[i]; j++) {
            p *= primes[i];
        }
    }

    std::cout << "Answer: " << p << std::endl;
}

std::vector<int> GetPrimes(int max) {
    bool *isPrime = new bool[max + 1];
    for(int i = 0; i <= max; i++) {
        isPrime[i] = true;
    }
    isPrime[0] = isPrime[1] = false;
    int p = 2;
    while(p <= max) {
        if(isPrime[p]) {
            for(int j = 2; p * j <= max; j++) {
                isPrime[p * j] = false;
            }
        }
        p++;
    }

    std::vector<int> primes;

    for(int i = 0; i <= max; i++) {
        if(isPrime[i]) primes.push_back(i);
    }

    delete []isPrime;
    return primes;
}

std::vector<int> Factor(int n, const std::vector<int> &primes) {
    std::vector<int> exponents(primes.size(), 0);
    while(n > 1) {
        for(int i = 0; i < primes.size(); i++) {
        if(n % primes[i] == 0) { 
        exponents[i]++;
            n /= primes[i];
        break;
        }
            }
    }
    return exponents;
}

Пример вывода:

Enter an integer: 20
Answer: 232792560
10 голосов
/ 24 января 2010

Существует более быстрый способ решения проблемы с использованием теории чисел. Другие ответы содержат указания, как это сделать. Этот ответ только о том, как лучше написать условие if в исходном коде.

Если вы хотите заменить только длинное условие, вы можете лучше выразить его в цикле for:

 if ((num%2) == 0 && (num%3) == 0 && (num%4) == 0    && (num%5) == 0 && (num%6) == 0 
&& (num%7) == 0 && (num%8) == 0 && (num%9) == 0 && (num%10) == 0 && (num%11) == 0 && (num%12) ==0   
&& (num%13) == 0 && (num%14) == 0 && (num%15) == 0 && (num%16) == 0 && (num%17) == 0 && (num%18)==0
&& (num%19) == 0    && (num%20) == 0)     
{ ... }

становится:

{
  int divisor; 
  for (divisor=2; divisor<=20; divisor++)
    if (num%divisor != 0)
      break;
  if (divisor != 21)
  { ...}
}

Стиль не велик, но я думаю, это то, что вы искали.

4 голосов
/ 24 января 2010

См. http://en.wikipedia.org/wiki/Greatest_common_divisor Учитывая два числа a и b, вы можете вычислить gcd (a, b), и наименьшее число, кратное обоим, является a * b / gcd (a, b). Очевидная вещь, которую нужно сделать, это сохранить некое подобие промежуточного итога и добавить числа, которые вас интересуют, один за другим: у вас есть ответ А, и вы добавляете следующее число X_i для рассмотрения, набирая

A '= A * X_i / (gcd (A, X_i))

Вы можете увидеть, что это на самом деле работает, рассматривая, что вы получите, если вы все разложите на множители и запишите их как произведения простых чисел. Это должно в значительной степени позволить вам выработать ответ от руки.

2 голосов
/ 24 января 2010

Совет:

вместо того, чтобы увеличивать число на 1 на каждом шаге, вы можете увеличить его на 20 (будет работать намного быстрее). Конечно, могут быть и другие улучшения, я подумаю об этом позже, если у меня будет время. Надеюсь, я немного тебе помог.

1 голос
/ 17 октября 2013
#include<vector>
using std::vector;
unsigned int Pow(unsigned int base, unsigned int index);

unsigned int minDiv(unsigned int n)
{
     vector<unsigned int> index(n,0);
     for(unsigned int i = 2; i <= n; ++i)
     {
         unsigned int test = i;
         for(unsigned int j = 2; j <= i; ++j)
         {
             unsigned int tempNum = 0;
             while( test%j == 0)
             {
                 test /= j;
                 tempNum++;
             }
             if(index[j-1] < tempNum)
                 index[j-1] = tempNum;
         }
     }
     unsigned int res =1;
     for(unsigned int i = 2; i <= n; ++i)
     {
         res *= Pow( i, index[i-1]);
     }
     return res;
 }

unsigned int Pow(unsigned int base, unsigned int index)
{
    if(base == 0)
        return 0;
    if(index == 0)
        return 1;
    unsigned int res = 1;
    while(index)
    {
        res *= base;
        index--;
    }
    return res;
}

Вектор используется для хранения коэффициентов наименьшего числа.

1 голос
/ 26 января 2010

Указанное число является наименьшим общим кратным числам от 1 до 20.

Поскольку я ленивый, пусть ** представляет возведение в степень. Пусть kapow (x, y) представляет целую часть журнала для основания x из y. (Например, капов (2,8) = 3, капов (2,9) = 3, капов (3,9) = 2.

Простые числа, меньшие или равные 20, равны 2, 3, 5, 7, 11, 13 и 17. LCM:

Поскольку sqrt (20) <5, мы знаем, что kapow (i, 20) для i> = 5 равно 1. По проверке LCM составляет

LCM = 2 Капов (2,20) * 3 Капов (3,20) * 5 * 7 * 11 * 13 * 17 * 19

что составляет

LCM = 2 4 * 3 2 * 5 * 7 * 11 * 13 * 17 * 19

или

LCM = 16 * 9 * 5 * 7 * 11 * 13 * 17 * 19

0 голосов
/ 24 октября 2015

Вот версия ответа C @ MAK на C #, возможно, в C # есть метод уменьшения списка, я нашел что-то в сети, но быстрых примеров нет, поэтому я просто использовал цикл for вместо reduce:

в Python
static void Main(string[] args)
    {
        const int min = 2;
        const int max = 20;
        var accum = min;

        for (var i = min; i <= max; i++)
        {
            accum = lcm(accum, i);
        }

        Console.WriteLine(accum);
        Console.ReadLine();
    }

    private static int gcd(int a, int b)
    {
        return b == 0 ? a : gcd(b, a % b);
    }

    private static int lcm(int a, int b)
    {
        return a/gcd(a, b)*b;
    }
0 голосов
/ 03 апреля 2013

это написано в с

#include<stdio.h>
#include<conio.h>
void main()
{

int a,b,flag=0;

for(a=1; ; a++)
{
    for(b=1; b<=20; b++)
    {
        if (a%b==0)
            {
                flag++;
            }

    }
    if (flag==20)
        {
            printf("The least num divisible by 1 to 20 is = %d",a);
            break;
        }
        flag=0;
}


getch();

}

0 голосов
/ 16 сентября 2010

Ruby Cheat:

require 'rational'

def lcmFinder(a = 1, b=2)
  if b <=20
    lcm = a.lcm b
    lcmFinder(lcm, b+1)
  end
  puts a
end


lcmFinder()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...