простая проблема C - PullRequest
3 голосов
/ 19 июня 2009

Я должен был начать изучать C как часть проекта, который я делаю. Я начал решать проблемы с «эйлером», и у меня проблемы с первым . Я должен найти сумму всех кратных 3 или 5 ниже 1000. Может кто-нибудь, пожалуйста, помогите мне. Спасибо.

#include<stdio.h>
int start;
int sum;

int main() {
    while (start < 1001) {
        if (start % 3 == 0) {
            sum = sum + start;
            start += 1;
        } else {
            start += 1;
        }

        if (start % 5 == 0) {
            sum = sum + start;
            start += 1;
        } else {
            start += 1;
        }
        printf("%d\n", sum);
    }
    return(0);
}

Ответы [ 10 ]

50 голосов
/ 19 июня 2009

Вы уже получили несколько хороших ответов, в основном предлагая что-то вроде:

#include <stdio.h>
int main(int argc, char * argv[])
{
  int i;
  int soln = 0;
  for (i = 1; i < 1000; i++)
  {
    if ((i % 3 == 0) || (i % 5 == 0))
    {
      soln += i;
    }
  }
  printf("%d\n", soln);
  return 0;
}

Так что я собираюсь пойти другим путем. Я знаю, что вы делаете это, чтобы выучить C, так что это может быть немного касательно.

Действительно, вы заставляете компьютер работать слишком усердно для этого :). Если бы мы заранее кое-что выяснили, это могло бы облегчить задачу.

Ну, сколько кратных 3 меньше 1000? По одному на каждый раз, когда 3 входит в 1000 - 1.

mult 3 = & lfloor; (1000 - 1) / 3 этаж; = 333

(& lfloor; и & rfloor; означают, что это этаж деление или, в терминах программирования, целое деление, где остаток отбрасывается).

А сколько кратных 5 меньше 1000?

мульт 5 = & lfloor; (1000 - 1) / 5 этаж; = 199

Теперь, какова сумма всех кратных 3, меньших 1000?

сумма 3 = 3 + 6 + 9 + ... + 996 + 999 = 3 раза; (1 + 2 + 3 + ... + 332 + 333) = 3 раза; & сумма; я = от 1 до нескольких 3 i

А сумма всех кратных 5 меньше 1000?

сумма 5 = 5 + 10 + 15 + ... + 990 + 995 = 5 & times; (1 + 2 + 3 + ... + 198 + 199) = 5 & times; & sum; я = от 1 до нескольких 5 i

Некоторые кратные 3 также кратны 5. Это кратные 15. Так как они учитываются в mult 3 и mult 5 (и, следовательно, сумма 3 и сумма 5 ), нам нужно знать mult 15 и сумма 15 , чтобы не считать их дважды.

mult 15 = & lfloor; (1000 - 1) / 15 этаж; = 66

сумма 15 = 15 + 30 + 45 + ... + 975 + 990 = 15 & times; (1 + 2 + 3 + ... + 65 + 66) = 15 & times; & sum; я = от 1 до нескольких 15 i

Таким образом, решение проблемы " найти сумму всех кратных 3 или 5 ниже 1000 " будет тогда

солнеч = сумма 3 + сумма 5 - сумма 15

Итак, если бы мы хотели, мы могли бы реализовать это напрямую:

#include <stdio.h>
int main(int argc, char * argv[])
{
  int i;
  int const mult3 = (1000 - 1) / 3;
  int const mult5 = (1000 - 1) / 5;
  int const mult15 = (1000 - 1) / 15;
  int sum3 = 0;
  int sum5 = 0;
  int sum15 = 0;
  int soln;

  for (i = 1; i <= mult3; i++) { sum3 += 3*i; }
  for (i = 1; i <= mult5; i++) { sum5 += 5*i; }
  for (i = 1; i <= mult15; i++) { sum15 += 15*i; }

  soln = sum3 + sum5 - sum15;
  printf("%d\n", soln);
  return 0;
}

Но мы можем сделать лучше. Для расчета отдельных сумм у нас есть тождество Гаусса , в котором говорится, что сумма от 1 до n (иначе: i = 1 до n i) равна n & times; (n + 1) / 2 Итак:

сумма 3 = 3 раза; мульт 3 раз (мульт 3 + 1) / 2

сумма 5 = 5 & times; мульт 5 & times; (мульт 5 + 1) / 2

сумма 15 = 15 & times; мульт 15 & times; (мульт 15 + 1) / 2

(Обратите внимание, что здесь мы можем использовать нормальное или целочисленное деление - это не имеет значения, поскольку одно из n или n + 1 должно делиться на 2)

Теперь это довольно аккуратно, поскольку это означает, что мы можем найти решение без использования цикла:

#include <stdio.h>
int main(int argc, char *argv[])
{
  int const mult3 = (1000 - 1) / 3;
  int const mult5 = (1000 - 1) / 5;
  int const mult15 = (1000 - 1) / 15;
  int const sum3 = (3 * mult3 * (mult3 + 1)) / 2;
  int const sum5 = (5 * mult5 * (mult5 + 1)) / 2;
  int const sum15 = (15 * mult15 * (mult15 + 1)) / 2;

  int const soln = sum3 + sum5 - sum15;
  printf("%d\n", soln);
  return 0;
}

Конечно, с тех пор, как мы зашли так далеко, мы могли провернуть все это вручную:

сумма 3 = 3 раза; 333 раза; (333 + 1) / 2 = 999 раз; 334/2 = 999 раз; 117 = 117000 - 117 = 116883

сумма 5 = 5 & times; 199 & times;; (199 + 1) / 2 = 995 & times; 200/2 = 995 & times; 100 = 99500

сумма 15 = 15 & times; 66 & times; (66 + 1) / 2 = 990 & times; 67/2 = 495 & times; 67 = 33165

солнеч = 116883 + 99500 - 33165 = 233168

И напишите гораздо более простую программу:

#include <stdio.h>
int main(int argc, char *argv[])
{
  printf("233168\n");
  return 0;
}
17 голосов
/ 19 июня 2009

Вы можете изменить свои ifs:

 if  ((start % 3 == 0) || (start % 5 == 0)) 
     sum += start;
 start ++;

и не забудьте инициализировать вашу сумму с нуля и начать с единицы. Кроме того, измените условие while на <1000. </p>

6 голосов
/ 19 июня 2009

Вы бы гораздо лучше обслуживали цикл for и комбинировали свои условные выражения.

Не тестировалось:

int main()
{
  int x;
  int sum = 0;

  for (x = 1; x <= 1000; x++)
    if (x % 3 == 0 || x % 5 == 0)
      sum += x;

  printf("%d\n", sum);
  return 0;
}
3 голосов
/ 19 июня 2009

Все ответы хороши, но не помогут вам выучить C.

Что вам действительно нужно понять, так это найти собственные ошибки. Отладчик может помочь вам, и самый мощный отладчик в C называется "printf". Вы хотите знать, что делает ваша программа, и ваша программа не является «черным ящиком».

Ваша программа уже печатает сумму, возможно, она неверна, и вы хотите знать, почему. Например:

printf("sum:%d start:%d\n", sum, start);

вместо

printf("%d\n", sum);

и сохраните его в текстовом файле, затем попытайтесь понять, что происходит не так.

  • отсчет начинается с 1 и заканчивается 999?
  • действительно ли оно идет от 1 до 999 без пропуска чисел?
  • работает ли он на меньшем диапазоне?
3 голосов
/ 19 июня 2009

Да, хорошо, я могу примерно видеть, куда вы идете, я думаю, что единственное, что не так с этим, было упомянуто ранее. Я делал эту проблему раньше, очевидно, вам нужно пройти через все кратные 3 и 5 и сложить их. Я сделал это так, и это работает:

int accumulator = 0;
int i;

for (i = 0; i < 1000; i += 3)
    accumulator += i;

for (i = 0; i < 1000; i +=5) {
    if (!(i%3==0)) {
        accumulator += i;
    }
}
printf("%d", accumulator);

РЕДАКТИРОВАТЬ: также обратите внимание, что это не от 0 до 1000 включительно, <1000 останавливается на 999, так как это последнее число ниже 1000, вы противопоставили это <1001, что означает, что вы идете до 1000, что кратно 5 Это означает, что ваш ответ будет на 1000 больше, чем должен быть. </p>

2 голосов
/ 30 июля 2009

Вы забыли инициализировать свои переменные,

2 голосов
/ 19 июня 2009

На самом деле вам нужен отладчик и пошаговое выполнение кода, чтобы вы могли увидеть, что он на самом деле делает. Ваша основная проблема заключается в том, что поток управления идет не туда, где вы думаете, и вместо того, чтобы предоставлять правильный код, как это сделали другие, я попытаюсь объяснить, что делает ваш код. Вот что происходит, шаг за шагом (я пронумеровал строки):

1:    while (start < 1001) {
2:        if  (start % 3 == 0) {
3:            sum = sum + start;
4:            start += 1;
5:        }
6:        else {
7:            start += 1;
8:        }
9:
10:       if (start % 5 == 0) {
11:           sum = sum + start;
12:           start += 1;
13:       }
14:       else {
15:           start += 1;
16:       }
17:       printf("%d\n", sum);
18:    }
  • строка 1. сумма равна 0, начало равно 0. Условие цикла истинно.
  • строка 2. сумма равна 0, начало равно 0. Если условие истинно.
  • строка 3. сумма равна 0, начало равно 0. сумма <- 0. </li>
  • строка 4. сумма равна 0, начало равно 0. начало <- 1. </li>
  • строка 5. сумма равна 0, начало равно 1. перепрыгнуть через предложение "else"
  • строка 10. сумма равна 0, начало равно 1. Если условие ложно, перейдите к предложению «else».
  • строка 15. сумма равна 0, начало равно 1. начало <- 2. </li>
  • строка 16 (пропущена)
  • строка 17. сумма равна 0, начало равно 2. Выведите «0 \ n».
  • строка 18. сумма равна 0, начало равно 2. Перейти к началу цикла.
  • строка 1. сумма равна 0, начало равно 2. Условие цикла истинно.
  • строка 2. сумма равна 0, начало равно 2. Если условие ложно, перейдите к предложению «else».
  • строка 7. сумма равна 0, начало равно 2. начало <- 3. </li>
  • строка 10. сумма равна 0, начало равно 3. Если условие ложно, перейдите к предложению «else».
  • строка 15. сумма равна 0, начало равно 3. начало <- 4. </li>
  • строка 17. сумма равна 0, начало равно 4. Выведите «0 \ n».

Вы видите, как это происходит? Вы, кажется, думаете, что в строке 4 после выполнения sum += 1 управление возвращается к началу цикла. Это не так, оно переходит к следующему пункту после конструкции if / else.

2 голосов
/ 19 июня 2009

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

По-видимому, вам действительно следует инициализировать начало и сумму до нуля, и, возможно, printf должен быть вне цикла.

1 голос
/ 19 июня 2009

Проблема с вашим кодом в том, что вы увеличиваете переменную 'start' в два раза. Это связано с наличием двух операторов if..else. Вам нужен оператор if..else if..else следующим образом:

           if  (start % 3 == 0) {
                    sum = sum + start;
                    start += 1;
            }
            else if (start % 5 == 0) {
                    sum = sum + start;
                    start += 1;
            }
            else {
                    start += 1;
            }

Или вы можете быть более краткими и написать это следующим образом:

if(start % 3 == 0)
    sum += start;
else if(start % 5 == 0)
    sum += start;
start++;

Любой из этих двух способов должен работать для вас.

Удачи!

0 голосов
/ 19 июня 2009

Вот общее решение, которое работает с произвольным числом факторов:

#include <stdio.h>

#define sum_multiples(BOUND, ...) \
    _sum_multiples(BOUND, (unsigned []){ __VA_ARGS__, 0 })

static inline unsigned sum_single(unsigned bound, unsigned base)
{
    unsigned n = bound / base;
    return base * (n * (n + 1)) / 2;
}

unsigned _sum_multiples(unsigned bound, unsigned bases[])
{
    unsigned sum = 0;

    for(unsigned i = 0; bases[i]; ++i)
    {
        sum += sum_single(bound, bases[i]);

        for(unsigned j = i + 1; bases[j]; ++j)
            sum -= sum_single(bound, bases[i] * bases[j]);
    }

    return sum;
}

int main(void)
{
    printf("%u\n", sum_multiples(999, 3, 5));
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...