1. Python / Говнокод #10924

    −101

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    maxi=140000
    plist=set(primes(maxi))
    dlist={}
    def dp(n):
        if dlist.has_key(n):
            return dlist[n]
        else:
            facts= len([k for k in plist if n%k==0])
            dlist[n]=facts
            return facts
    print [k for k in range (1,maxi) if dp(k)==4 and dp(k+1)==4 and dp(k+2)==4 and dp(k+3)==4]

    http://projecteuler.net/problem=47
    http://projecteuler.net/thread=47;page=8


    Этот товарищ растянул на 11 секунд то, что даже тупым брутфорсом решается за <1 секунду.

    Запостил: TheHamstertamer, 12 Июня 2012

    Комментарии (54) RSS

    • Там еще дальше один фрукт на Джаве решил за 15 сек.
      Ответить
      • Линк в студию.
        Ответить
        • http://projecteuler.net/thread=47;page=7
          11тый пост сверху
          Ответить
          • Блин. У него же есть primeset, а делит какого-то хрена не на числа, взятые из него, а на все подряд от 2 до корня...

            > for (int i = 2 ; i <= Math.sqrt(number) ; i++)
            Ява умеет оптимизировать такие штуки? Или это будет гонять sqrt на каждой итерации?
            Ответить
          • > if (prime>value/2) ...
            if (prime*prime > candidate) же!

            Печальный код :(
            Ответить
    • Не понял, тут же всё чётко, и перебираются только простые, и результат кэшируется.
      Ответить
      • На первый взгяд - да.
        Но это только на первый.

        Если всмотреться - делается full-scan списка всех простых чисел.
        ([k for k in plist if n%k==0])
        Оно вроде и выглядит компактно, логично, красиво, но внутри пиздец.

        ЗЫ. А в пухтоне вот так можно писать:
        return ( dlist[n]= len([k for k in plist if n%k==0]) )
        Ответить
        • > Если всмотреться - делается full-scan списка всех простых чисел.

          Да сколько их там? n/log(n) вроде, да, тогда многовато.

          > ЗЫ. А в пухтоне вот так можно писать:

          И чё, для кешированного значения оно сразу вернёт значение?
          Ответить
        • > А в пухтоне вот так можно писать:
          Вроде присваивания внутри выражений там недопустимы. Не уверен, т.к. не знаю питон, и имею к нему индивидуальную непереносимость.
          Ответить
          • >Не уверен, т.к. не знаю питон, и имею к нему индивидуальную непереносимость.
            Такая же херня.
            Это я типа так спросил. Можно ли.
            Ответить
      • :)
        Ответить
    • import Data.List
      
      primes = 2 : filter isPrime [3..]
      isPrime x = check primes where
          check (p:ps) | p*p > x        = True
                       | x `mod` p == 0 = False
                       | otherwise      = check ps
      
      factors n = step n primes where
          step 1 _ = []
          step n pp@(p:ps)
              | p*p > n        = [n]
              | n `mod` p == 0 = p : step (n `div` p) pp
              | otherwise      = step n ps
      
      counts = map (length . nub . factors) [1..]
      shifted = zip5 [1..] counts (drop 1 counts) (drop 2 counts) (drop 3 counts)
      fours = filter (\(_,a,b,c,d) -> a==4 && b==4 && c==4 && d==4) shifted
      
      main = print result where (result,_,_,_,_) = head fours

      Решение в лоб на хаскеле 0.21с. А если дописать primes :: [Int] то 0.08с :)

      А автор, конечно жжот, сканируя ВЕСЬ список простых чисел :)
      Ответить
      • На питоне всё-равно будет короче, достаточно заменить полный скан на что-то вменяемое.
        Ответить
        • Таки не короче.

          isPrime n = n > 1 && coprime primes n
          coprime factors n = foldr (\f r-> f*f>n || (rem n f /= 0 && r)) True factors
          primes = 2 : 3 : filter (coprime $ tail primes) [5,7..]
          
          factorize_ n | n > 1 = concat [divs n p | p <- [2..n], isPrime p]
            where divs n p = if rem n p==0 then p:divs (quot n p) p else []
          
          
          main = print $ head [x | x <- [2..], let y = x + 1; z = y + 1; c = z + 1, all (== 4) $ map (length . nub . factorize) [x, y, z, c]]


          Haskell - 6
          Python - ~11
          Ответить
          • Ну и на питоне еще генератор простых чисел не приведен.

            P.S. А че не в одну строку все ? )
            Ответить
            • >P.S. А че не в одну строку все ? )
              Показать свою джедайскую силу.
              Ответить
              • Речь о читерских сравнениях "строк".
                В путхоне самая длинная
                print [k for k in range (1,maxi) if dp(k)==4 and dp(k+1)==4 and dp(k+2)==4 and dp(k+3)==4]
                И то её можно написать короче.
                Ответить
                • Ага, именно об этом :)
                  Если уж меряться длиной кода - то символами а не строками.
                  Ответить
                  • Символами так символами.
                    Haskell - 516
                    Python - 298

                    В таком случае все же короче.
                    Ответить
                    • К питону все же стоит приплюсовать генератор простых чисел.
                      Ответить
                • Ага, логичнее сравнивать количество непробельных символов. По договоренности не учитывая import ...
                  Ответить
                  • А еще лучше - не заниматься этой фаллометрией ;)
                    Ответить
                    • Боитесь меряться с питоном? Что ж, вас можно понять).
                      Ответить
          • Кстати запустил этот код. Ответа так и не дождался.

            Что за отвратная факторизация по p <- [2..n], isPrime p, выше же у вас описан primes... Да еще и фулл-скан как в оригинальном посте... Или это просто попытка переписать код дословно?
            Ответить
            • >Или это просто попытка переписать код дословно?
              Сортоф.

              Он медленный от того, что я на своей машине использовал следующий код:
              factorize n | n > 1 = go n primesList
                 where
                   go n ds@(d:t)
                      | d*d > n    = [n]
                      | r == 0     =  d : go q ds
                      | otherwise =      go n t
                          where 
                            (q,r) = quotRem n d


              А в примере для краткости заменил его на код выше.
              Такие дела.
              Ответить
              • Понятно, ну значит производительность должна быть примерно в том же районе, что и у моего.

                Хотя вот вопрос: в последней строке считается map (length . nub . factorize) [x, y, z, c], а перед этим пачка let'ов.
                1) Почему бы не убрать let и не сделать [x, x+1, x+2, x+3]?
                2) Получается в 4 раза больше факторизаций, чем в моем варианте?
                Ответить
                • 1) Можно и так.
                  2) Да вроде, я сильно оптимизацией не заморачевался, подумал, что если будет тупить, то перепишу, но оно и так выполняется за <1 сек.
                  Ответить
          • http://ideone.com/xpuf8
            Говно.
            У борланда лучше норм:
            http://ideone.com/3bCAe
            Ответить
            • м. Борманд. Просто, судя по расстоянию между "л" и "м" на клавиатуре - явно не очепятка.
              Ответить
          • Как много, можно за 5 (не считая последнюю строку: ее можно было бы и подтянуть):

            seq 647 1000000 | factor | awk '
              NF <= 4 {conseq = 0; next}
              { n = NF-1; for (i=2;i<=NF;i++) if ($i == $(i-1)) n -= 1;
                if (n == 4) {conseq += 1} else {conseq = 0}
                if (conseq == 4) {print $0; exit} 
              }'
            Ответить
          • Немного извращений:

            seq 999999|factor|eddie -lLmData.List.Utils 'map fst.take 1.dropWhileList((/=[4,4,4,4]).map snd.take 4).map(\s->let(n:f)=words s in(n,length$nub f))'
            Ответить
        • Да я не спорю. Я просто взял написанные ранее функции primes и factors, дописал к ним 4 тупых строчки да выложил сюда ;)

          P.S. У этого кода на хаскеле есть плюс - из-за работы с бесконечным списком не нужно подбирать верхнюю планку для простых чисел (140000 в оригинальном решении).
          Ответить
          • Ну вообще-то в питоне есть генераторы (см ключевое слово yield), так что вполне реально сделать список-кэш и наращивать его числами по мере необходимости. Типа
            def primes():
              while True:
                #тут вычисляем очередное простое prime
                yield prime
            #
            
            primeiter = primes()
            maxprime = 0
            primeset = set()
            #и потом делать как-то так
            while n>maxprime:
              maxprime = primeiter.next()
              primeset.add(maxprime)
            print n in primeset
            Ответить
            • Хм.. во-первых yield тут не совсем в тему - это лишь частный случай генератора, скорее ключевой момент - поддержка синтаксиса in (через .next() или как там).
              Во-вторых, генератор-то линеен, если нужен кэш, то не проще ли functools.lru_cache?
              Ответить
              • New in version 3.2. А я как-то ко второму питону привык.

                И потом, что именно заворачивать в lru_cache? primes()? Так оно аргументов не просит, кэш не сработает. Код целиком как функцию? Не ну можно конечно, но большой ли будет выигрыш?
                Ответить
                • Заворачивать is_prime(n), разумеется. Не нужно будет задавать границу. А реализация использует dict (хеш-таблица). Насколько знаю, set тоже хеш-таблица.
                  Ответить
                  • Понимаешь, тут получается двойной кэш - внутри is_prime() (я полагаю что primeset сохраняется между вызовами) и снаружи. Есть ли смысл тогда?
                    Ответить
                    • Точно, тут лучше иметь явный dict для разложения. Но с другой стороны - то, что lru_cache не предоставляет оный - это проблема реализации, а не подхода.
                      Можно написать свой простенький вариант, вряд ли получится длинее, чем генератор + Set.
                      Но maxprime - явный хак: если не знать порядок, то получится либо оверхэд, либо усложнение (проверять не отстал ли он и подтягивать при необходимости).
                      Ответить
                      • Ну проверять не отстал ли кэш всё равно надо. На то он и кэш, чтобы его время от времени подновлять. А maxprime - это sort of оптимизация. Чтобы не делать max(primeset) каждый раз.
                        Вообще есть более интересный вариант:
                        if n<=maxprime:
                          return n in primeset
                        while n>maxprime:
                          maxprime = primeiter.next()
                          primeset.add(maxprime)
                          if n==maxprime:
                            return True
                        else:
                          return False

                        Для тех кто не знает питона: последний else относится к while, и сработает если произойдёт нормальный выход из цикла по условию, а не по break/return/exception.
                        Т.е. мы точно знаем что в кэше числа нет, и не трогаем его, а вместо этого проверяем свежеполученные числа. При этом кэш все равно обновляется.
                        Правда, может получиться дурацкая ситуация когда промах кэша будет отрабатывать быстрее чем попадание.
                        Ответить
                        • А на кой такой елсе нужен?
                          Ответить
                          • Синтаксический сахар. Абстрактный пример:
                            dictionary = {'J':'Java', 'L':'Lisp', 'H':'Haskell'}
                            mask = 'Brainfuck'
                            for key,value in dictionary.iteritems():
                              if value==mask:
                                print 'Found {0} with key {1}'.format(value, key)
                                break
                            else:
                              print 'Value {0} not found.'.format(mask)

                            Без такой конструкции пришлось бы вводить флаг "элемент найден". Пустячок, а приятно, и никто пользоваться не заставляет.
                            Такой else есть у циклов for, while, и у блока try. В последнем случае он выполнится только если при выполнении try НЕ произошло исключения. Привести пример для этого я затрудняюсь, правда.
                            Ответить
                            • А, я понял, да, действительно экономия на флаге.
                              Ответить
                            • Как пишут в туториале по питону, который я наконец-то решил осилить:
                              "The use of the else clause is better than adding additional code to the try clause because it avoids accidentally catching an exception that wasn’t raised by the code being protected by the try ... except statement."
                              for arg in sys.argv[1:]:
                                  try:
                                      f = open(arg, 'r')
                                  except IOError:
                                      print 'cannot open', arg
                                  else:
                                      print arg, 'has', len(f.readlines()), 'lines'
                                      f.close()

                              Т.е. если в readlines у нас вылетит ошибка чтения - мы не выдадим кривое сообщение "не могу открыть файл".
                              Ответить
    • показать все, что скрытоХуй соси, собака.
      Ответить
    • показать все, что скрытоКакой багор )))
      Ответить

    Добавить комментарий