Внимательно изучите ваше условие продолжения (где n
- произвольное целое число, возможно, разное в каждом случае использования, поэтому, например, a != 3n
просто означает, что a
не делится на три). Я покажу процесс:
while((a % 3 != 0 || a % 2 != 0) && (b % 2 != 0 || b % 3 != 0))
( a != 3n OR a != 2n ) AND ( b != 2n OR b != 3n )
( a != 6n ) AND ( b != 6n )
Он говорит: продолжайте, пока оба a
не делятся на два, и три, и b
не кратно двум и трем. Другими словами, он будет продолжаться только в том случае, если оба a
и b
кратны шести. С другой стороны, он, конечно, выйдет, если a
или b
не делится на шесть.
Поскольку входное значение 13
устанавливает a = 6
и b = 7
, случай продолжения ложен на первой итерации (семь не кратно шести).
Возможно, было бы лучше переосмыслить способ определения допустимости определенных числовых комбинаций (а) . Например (предполагая, что числа должны быть от 1
до N - 1
, поскольку в противном случае ваше пространство решений, вероятно, будет бесконечным), вы можете использовать что-то вроде:
#include <iostream>
int main() {
// Get the number.
int num;
std::cout << "Number? ";
std::cin >> num;
// Check all i + j = n for 1 <= i,j < n.
for (int i = 1, j = num - 1; i < j; ++i, --j) {
// Disregard if either number not a multiple of 2 or 3.
if ((i % 2) != 0 && (i % 3) != 0) continue;
if ((j % 2) != 0 && (j % 3) != 0) continue;
std::cout << num << " => " << i << ", " << j << "\n";
return 0;
}
std::cout << num << " => no solution\n";
return 0;
}
Примечание. Я использую i < j
как условие продолжения for
, предполагая, что они должны быть отдельными числами. Если им разрешено использовать тот же номер , измените его на i <= j
.
(a) Использование всех and
, or
и not
(даже неявно, путем изменения условий продолжения и выхода) иногда доставляет больше проблем, чем оно того стоит, поскольку теоремы Де Моргана, как правило, вступают в игру:
_____ _ _
A ∩ B ⇔ A ∪ B : (not(A and B)) is ((not A) or (not B))
_____ _ _
A ∪ B ⇔ A ∩ B : (not(A or B)) is ((not A) and (not B))
В таких случаях код может стать более читаемым, если вы разберете отдельные проверки.
Интересно, что если вы запустите этот код с довольно большим количеством входных значений, вы увидите шаблон что, если решение существует, одно из чисел в этом решении всегда равно двум или трем.
Это потому, что, кроме патологических случаев, суммы меньше пяти (или меньше четырех, если решение позволяет имеют одинаковые числа):
- каждое четное число
2n, n > 1
является суммой 2
и 2n - 2
, обоих кратных двум (2n - 2 = 2(n - 1)
); и - каждое нечетное число
2n + 1, n > 2
представляет собой сумму 3
и 2n + 1 - 3
, первое из которых кратно трем, а второе - кратному двум (2n + 1 - 3 = 2n - 2 = 2(n - 1)
).
Итак, на самом деле l oop не требуется:
if (num < 5) { // 4 if allowing duplicates.
std::cout << num << " => no solution\n";
} else {
int first = (num % 2) == 0 ? 2 : 3;
std::cout << num << " => " << first << ", " << (num - first) << "\n";
}
Это на самом деле дает другой результат для некоторых чисел, например 17 = 2 + 15 = 3 + 14
, но оба решения по-прежнему верны.