Решение задач ProjectEuler №3 и № 4.
Запись от Тамика размещена 21.07.2014 в 13:43
Показов 5114
Комментарии 18
Метки c++
|
Задача №3. Простые делители числа 13195 это 5, 7, 13 и 29. Какой максимальный простой делитель у числа 600851475143? Решение. Как бы я ни старалась упростить код, выполнение всё равно занимает много времени. Тут уже ничего не поделаешь, потому как входное число большое. Но если у кого есть советы по оптимизации - буду благодарна. ![]() З.Ы. Решето Эратосфена тут не подойдет, потому как создать вектор с сайзом 600851475143 жестоко по отношению к памяти. ![]() Потому решила эту задачу более прямо, хотя решение занимает почти полторы секунды. ![]() Кликните здесь для просмотра всего текста
Задача №4. Палиндромные числа читаются одинаково как слева направо, так и наоборот. Самый большой палиндром, который можно получить умножением двух двузначных чисел - 9009 = 91*99. А теперь найдите самый большой палиндром, который можно получить умножением трёхзначных чисел. Решение. Кликните здесь для просмотра всего текста
| ||||||||||
Метки c++
Размещено в Решение задач ProjectEuler.
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 18
Комментарии
-
Я стараюсь решать подобные задачки на каком-нибудь функциональном языке. Вот, к примеру, вторая на Haskell
Довольно наглядно и терпимо по времениHaskell 1 2 3 4 5 6 7 8
Prelude> let isPalindrome x = s == reverse s where s = show x Prelude> let numbers = [100..999] Prelude> let products = numbers >>= (\x -> map (x*) numbers) Prelude> let palindromes = filter isPalindrome products Prelude> :set +s Prelude> maximum palindromes 906609 (0.55 secs, 575070128 bytes)

Запись от soon размещена 21.07.2014 в 22:47
-
0,048535662 сек.
Вроде тоже терпимо.
А сколько Ваш Хаскель возьмёт за третью задачу?Запись от Тамика размещена 22.07.2014 в 09:39
-
Вот вам решение 3 задачи намного быстрее(но на c#)
C# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
static bool is_Prime(long value)//не для всех. Те, что кратны 2 пройдут проверку, но они сюда не попадают { for (long i = 3; i < value/2; i += 2) if (value % i == 0) return false; return true; } static long solve(long value) { long num = 3; long answer = 2;//минимально возможный простой делитель у числа while (value % 2 == 0) value /= 2; while (value != 1) for (long i = num; i <= value; i += 2) if (value % i == 0) { value /= i; if (is_Prime(i)) answer = i; num = i; break; } return answer; } static void Main(string[] args) { System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); long value = 600851475143; sw.Start(); long answer = solve(value); sw.Stop(); Console.WriteLine(answer); Console.WriteLine(sw.Elapsed); }
Запись от rutelun размещена 22.07.2014 в 12:07
-
Ну зачем мне шарп? Я на плюсах пишу. Вот на них и интересует более быстрое решение.
Но спасибо за предложенный вариант.Запись от Тамика размещена 22.07.2014 в 12:45
-
Сколько?Запись от Тамика размещена 22.07.2014 в 12:46
-
На них почти так же будет. Время 00:00:00.0011786Запись от rutelun размещена 22.07.2014 в 13:12
-
на плюсах вроде бы так будетC++ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
#include <iostream> #include <cstdlib> #include <chrono> #include <vector> #include <cassert> bool is_prime(unsigned long long value) { for (unsigned long long i = 3; i < value / 2; i += 2) if (value % i == 0) return false; return true; } unsigned long long solve(unsigned long long value) { unsigned long long num = 3; unsigned long long answer = 2;//минимально возможный простой делитель у числа while (value % 2 == 0) value /= 2; while (value != 1) for (long i = num; i <= value; i += 2) if (value % i == 0) { value /= i; if (is_prime(i)) answer = i; num = i; break; } return answer; } int main() { assert(solve(10) == 5); auto now = std::chrono::high_resolution_clock::now(); auto answer = solve(600851475143); auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - now); std::cout << "Answer = " << answer << "\n"; std::cout << "Time : " << elapsed.count() << "ns.\n"; return 0; }
Запись от rutelun размещена 22.07.2014 в 13:19
-
Ваш код на g++ выдаёт такое.
Answer = 6857
Time : 127760ns.
Грац! Это и правда быстрее.
Благодарю.Запись от Тамика размещена 22.07.2014 в 13:26
-
Можно еще ускорить, если заменить
наC++ 1
for (unsigned long long i = 3; i < value / 2; i += 2)
Старая:C++ 1
for (unsigned long long i = 3; i * i <= value; i += 2)
Новая:Code 1 2
Answer = 6857 Time : 48763ns.
Code 1 2
Answer = 6857 Time : 29487ns.
С третьей сложнее. Наивное решение хоть и выглядит прилично, но, боюсь, так и не закончит вычисления. Всякие уловки, вроде вероятностных тестов дико выглядят, но не приносят вменяемого результата. Так что я пока в процессе
Запись от soon размещена 24.07.2014 в 08:28
-
Если оно не хранится, это еще не значит, что не используется ;-)
Хозяйке на заметку: в задаче №3 функция is_prime() лишняя совсем: если на очередной кандидат в простые поделилось без остатка -- этот кандидат не может быть составным числом (все простые, что меньше этого текущего кандидата, уже исключены из разложения на предыдущих шагах).
А если вспомнить, что шаг между кандидатами в простые в исследуемом диапазоне чередуется как 2, 4:C++ 15 16 17 18 19 20 21 22 23 24 25 26 27
unsigned long long solve(unsigned long long value) { unsigned long long answer = 0; while (value % 2 == 0) { value /= 2; answer = 2; } for (unsigned long i = 3; i * i <= value; i += 2) { while (value % i == 0) { value /= i; answer = i; } } return answer > value ? answer : value; }
Стоит ли выносить answer=...; из цикла или с этим и оптимизатор сам справится предлагается выяснить самостоятельно.C++ 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
unsigned long long solve(unsigned long long value) { unsigned long long answer = 0; while (value % 2 == 0) { value /= 2; answer = 2; } while (value % 3 == 0) { value /= 3; answer = 3; } for (unsigned long i = 5, delta = 2; i * i <= value; i += delta, delta ^= 6) { while (value % i == 0) { value /= i; answer = i; } } return answer > value ? answer : value; }
Речь про
C++ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
unsigned long long solve(unsigned long long value) { unsigned long long answer = 0; if (!(value % 2)) { answer = 2; do value /= 2; while (!(value % 2)); } if (!(value % 3)) { answer = 3; do value /= 3; while (!(value % 3)); } for (unsigned long i = 5, delta = 2; i * i <= value; i += delta, delta ^= 6) { if (!(value % i)) { answer = i; do value /= i; while (!(value % i)); } } return answer > value ? answer : value; }
Запись от bormant размещена 13.12.2018 в 15:52
-
Ну, во-первых такой сайз и не нужен. достаточно условия size*size > 600851475143
Во-вторых можно предложить хорошую упаковку решета. В каждой тридцатке (не считая первой) есть всего 8 чисел, подозрительных на простоту. То есть информацию о простоте 30 чисел можно уложить в 8 битов, и - какая удача! - ровно в 1 байт
Не знаю, помогут ли эти соображения справиться с вашим монстром, но кой-какую экономию памяти они дают.
Экзерсисы на эту тему от вашего покорного слуги где-то уже были на форуме. Если интересно, попробую поискать.
Для вашего конкретного числа потребуется память порядка 250000 байт, что уже вполне реально.
Конечно, это не панацея, потребность в памяти сокращается только в разы, но все-таки...Запись от Байт размещена 14.12.2018 в 13:46
-
Все просты делители числа 600851475143:
Result:
1
71
839
1471
6857
Time: 0.001000 sec. Solutions: 5
Быстрый алгоритмы поиска простых/всех делителей натурального числа (в т.ч. факторизация натурального числа)С++Запись от bedvit размещена 14.12.2018 в 15:10
-
Запись от bedvit размещена 14.12.2018 в 15:14
-
Конечно, все зависит от алгоритма и числа.
К примеру такое число, см. ниже из 35 знаков раскладывается на простые множители за 0.022 секунды, потому что у него много делителей, быстро убывает остаток неразложенного числа, отсекая заведомо ненужные расчеты.
Enter the numeric: 32145698745623154896521456325789541
Result:
1
3
43
89
421
1471
3139
3827
18559
279371
72587646
Time, sec (min): 0.022000 (0.000367) Solutions: 11
А такое см. ниже.(40 знаков) уже за 165.8 секунды, потому как делителей меньше, само число больше, меньше этапов отсечения лишних расчетов, больше времени на перебор.
Enter the numeric: 1236541236987456214532145698745632554159
Result:
1
7
61
11969
468883099
27339429457
18874212319751
Time, sec (min): 165.806000 (2.763433) Solutions: 7Запись от bedvit размещена 14.12.2018 в 18:02
-
Ого, спасибо большое за комментарии!
Вот как раз пришла к Вашему способу, потому на видео моего канала уже решено быстро и просто
Как раз Вашим методом 
Запись от Тамика размещена 18.12.2018 в 13:15
-
Рада Вас снова видеть у себя в блоге! Заходите почаще
Конечно интересно
Запись от Тамика размещена 18.12.2018 в 16:07
-
Искать долго не пришлось. Ибо уважаемый bedvit дал ссылку на свой блог, где это обсуждалась https://www.cyberforum.ru/blog... g4754.html
Но хочу заметить, что его исследования на эту тему и глубже, и интереснее, чем все что может предложить ваш покорный слуга.
Запись от Байт размещена 18.12.2018 в 22:08
-
Байт, благодарю за оценку и содержательные комментарии в моем блоге.
Тамика, конечно есть и более быстрые алгоритмы, к примеру Общий метод решета числового поляЗапись от bedvit размещена 20.12.2018 в 21:53





