Python-оптимизация алгоритма динамического программирования из codechef

Материал из DISCOPAL
Перейти к: навигация, поиск
Строка 65: Строка 65:
 
А потом парсить и отдавать результаты генератором.
 
А потом парсить и отдавать результаты генератором.
  
 +
Делаем {{diff|1=digprime.py|20478|такие правки}} и получаем
  
{{oldid|1=digprime.py|2=20468|3=Первая версия digprime.py}}  
+
{{oldid|1=digprime.py|2=20468|версию, которая работает абсолютно также}} по результату, возможно чуть медленней перекопированием ввода в память (если померять у себя), но возможно быстрее, чем у них на сервере, с задушенным IO.
{{diff|1=digprime.py|20478}}
+
 
 +
В любом случае, сначала надо избавиться от NZEC, потом уже заниматься оптимизацией.
 +
 
 +
[https://www.codechef.com/viewsolution/63961222 Ага, от NZEC уже избавились],
 +
но теперь здравствуй TL.
 +
 
 +
[[File:Python-оптимизация алгоритма динамического программирования из codechef_2022-05-01_03-36-58_image0.png||400px]]
 +
 
 +
Может если [https://www.codechef.com/viewsolution/63961211 перейти на PYPY], скомпилируется и пройдет?
 +
 
 +
Увы, нет.
 +
 
 +
[[File:Python-оптимизация алгоритма динамического программирования из codechef_2022-05-01_03-34-48_image0.png||400px]]
 +
 
 +
Обращаю внимание — 10.01 и 4 секунды это не время работы программы! Это сколько

Версия 00:38, 1 мая 2022

При разборе ваших решений, столкнулся с одной из попыток, с результатом «вроде все сделано правильно, но система не пропускает, наверно что-то не так с системой или вообще питон не потянет, вот на плюсах все решают и все хорошо».

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

Первая версия digprime.py

Видим вроде типичный алгоритм ДП, смотрим описание задачи Codechef/DIGPRIME, переходим по ссылке Editorial на разбор и разъяснение задачи, но даже если этой ссылки не будет, смотрим список принятых решений:

Python-оптимизация алгоритма динамического программирования из codechef 2022-05-01 02-47-12 image0.png

Берем из них любое принятое CPP-решение, сохраняем его в файл digprime-good.cpp компилируем его

 gcc -g -o digprime-good digprime-good.cpp -lstdc++

Итак, у нас есть референсное решение.

Смотрим на описание задачи, особенно на секцию «ограничения»…

Python-оптимизация алгоритма динамического программирования из codechef 2022-05-01 02-50-11 image0.png

и пишем примитивных генератор «digprime-generate.py», такой, чтобы задействовать все ограничения (вдруг все проходит на минимальных данных, но где-то что-то переполняется на самых крайних случаях), плюс большой тестсет даст возможность разумно измерять время работы.

import numpy as np
num = 100000
print(num)
for t in range(num):
    print(np.random.randint(1,1000000000000000000))

Генерим наш тестовый набор:

python digprime-generate.py > big-samples.txt

Генерим результаты нашего алгоритма и референсной реализации на тех же входных данных:

digprime-good < big-samples.txt > reference-good.txt
python digprime.py < big-samples.txt > big-our-results.txt

Сравниваем («meld», «winmerge», «fc», ) — используйте то, что ставится на вашу ось и есть под рукой, но в данном случае, совпадение добайтовое даже по ответу «md5sum»:

md5sum big-our-results.txt
  e602cd2d36e9c6749764cace13774bdc  big-our-results.txt
md5sum reference-good.txt
  e602cd2d36e9c6749764cace13774bdc  reference-good.txt

Вроде же все в абсолютном порядке, но что выдает codechef?

Python-оптимизация алгоритма динамического программирования из codechef 2022-05-01 02-58-12 image0.png

Ошибка «NZEC» — «какая-то ошибка», увы, без малейших подсказок на чем, и что за ошибка. Но по времени работы — доли секунды, предположим, что что-то сразу с вводом.

Тут на самом деле наблюдались разные проблемы в этих (codechef, spoj) тестовых системах. То что-то не так с буферизацией, и какой-то перевод строки становился пробелом, или длинная строка, и input() не вычитывал ее до конца, то большое количество операций input, а там перенаправление на чтение из файла, много IO операций, срабатывают какие-то контейнерные ограничения или просто будет тормозить.

Поэтому, лучше сразу сделать чтение типа

    lines = sys.stdin.readlines()
    content = " ".join(lines).strip()

А потом парсить и отдавать результаты генератором.

Делаем такие правки и получаем

Old revision of <tvar name=1>версию, которая работает абсолютно также</tvar> по результату, возможно чуть медленней перекопированием ввода в память (если померять у себя), но возможно быстрее, чем у них на сервере, с задушенным IO.

В любом случае, сначала надо избавиться от NZEC, потом уже заниматься оптимизацией.

Ага, от NZEC уже избавились, но теперь здравствуй TL.

Python-оптимизация алгоритма динамического программирования из codechef 2022-05-01 03-36-58 image0.png

Может если перейти на PYPY, скомпилируется и пройдет?

Увы, нет.

Python-оптимизация алгоритма динамического программирования из codechef 2022-05-01 03-34-48 image0.png

Обращаю внимание — 10.01 и 4 секунды это не время работы программы! Это сколько