1. C# / Говнокод #13175

    +133

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    int sum = 100;
                int sch = 0;
    
                for (int a50 = 0; a50 <= sum / 50; a50++)
                {
                    for (int a25 = 0; a25 <= (sum - a50 * 50) / 25; a25++)
                    {
                        for (int a10 = 0; a10 <= (sum - a50 * 50 - a25 * 25) / 10; a10++)
                        {
                            for (int a5 = 0; a5 <= (sum - a50 * 50 - a25 * 25 - a10 * 10) / 5; a5++)
                            {
                                sch++;
                            }
                        }
                    }
                }
     
    Console.WriteLine(Convert.ToString(sch));

    Задача: Подсчитайте сколькими способами можно разменять 1 доллар монетами достоинством 1, 5, 10, 25 и 50 центов. Решать можно как угодно - в лоб перебором, или в общем случае (для произвольной суммы размера и набора монет).

    У кого какие варианты еще будут?)

    Запостил: ipro, 14 Июня 2013

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

    • Так решение же давным-давно опубликовано. В чем смысл его еще раз искать?
      Ответить
    • SICP, первая глава, пример древовидной рекурсии.
      Ответить
      • Точно, рекурсией. А что такое sicp?
        Ответить
        • Неожиданно: http://ru.wikipedia.org/wiki/SICP
          Ответить
          • Хуита какая-то.
            Ответить
            • Анонимб школьник-пайтонист низвергает авторитеты.
              Помнится где-то разоблачал Кнута. Или то Царь, был?
              Ответить
              • Назови применение ФЯ, кроме /pr/
                Ответить
                • Диссертации всякие.
                  Ответить
                • Изначально речь шла о книге, а не о функциональных языках. Подходы описанные там очень полезны и применимы к императивным языкам в такой же мере. Лисп выбран всего-лишь в качестве языка для иллюстрации примеров и концепций.

                  Не понять этого может только идиот и/или не читавший книгу.

                  Кнут в своих трудах использовал специальный mix-assembler. Применяют ли его где-то? Нет. Какое практическое значение трудов Кнута? Оно огромно.

                  Но более всего меня удивляет вопрос о применимости ФЯ, который задан с того же акка, с которого не так давно за мной бегали и вопрошали о лямбдах в жаве.
                  Ответить
                  • Чувствуешь разницу - ФЯ или язык с элементами ФП? Повторяю вопрос: назовите применение ФЯ, кроме /pr/

                    >или не читавший книгу.
                    Ой, я что-то пропустил?

                    А с лямбдами в яве все просто: в почти 2014 году ИХ НЕТ
                    Ответить
                    • Ты видишь в названии книги слова "функциональный" или "язык"? Книга описывает вещи, которые не имеют отношения ни к конкретному языку, ни к чистой функциональщине. Лисп используется лишь потому, что синтаксис используемого диалекта можно описать в двух параграфах.

                      > Ой, я что-то пропустил?
                      Книга стоит того, чтобы её прочитать. Русский перевод кошерен.
                      Ответить
                      • Повторяю вопрос: назовите применение ФЯ, кроме /pr/
                        Ответить
                        • > назовите применение ФЯ, кроме /pr/

                          что есть /pr/?

                          Есть несколько компаний, которые пишут на хачкеле, окамле, кложуре, больше всех, думаю, эрланге. Писать всякие потоковые датадробилки, парсеры, анализаторы и кодогенераторы на фя одно удовольствие. Помню, у лицокниги вроде бы статический анализатор похапе кода был на окамле, pfff.

                          Можно сходить в гугл и спросить companies using X
                          http://ocaml.org/learn/companies.html
                          http://www.haskell.org/haskellwiki/Haskell_in_industry
                          http://www.erlang.org/faq/introduction.html


                          Ну и наконец, повторюсь, что твой вопрос не имеет отношения к книге. В книге просто собрано много интересных и красивых идей, связанных с программированием.
                          Ответить
                      • Да нет, я про нее конечно слышал, но основы алгоритмов и структур данных знаю и без нее. Стоит ли мне это чудо 25летней давности читать или таки ну его нахуй и лучше, например, html подучить?
                        Ответить
                        • По случайному совпадению в книге "Структура и Интерпретация Программ" почти ничего не написано про алгоритмы и структуры данных...

                          Мне, собственно, глубоко индифферентно, будешь ты её читать или нет.
                          Ответить
                          • Нет, ты уверяешь, что мне стоит ее прочитать, у меня возник вопрос: что я там узнаю нового и почему стоит читать именно это старье?
                            Ответить
                          • В данном случае это классический:
                            "Не читал, но осуждаю".
                            Настоятельно рекомендую прекратить тратить бисер.
                            Ответить
                            • Не читал, слышал из других источников.

                              П.С. Просто съеби.
                              Ответить
                              • >>>слышал из других источников
                                >>"Секс - это скучно. Мне подруга говорила."
                                Ответить
                                • Слышал те же самые вещи из других источников.

                                  Твоя подруга тебе такое говорит? Трахайся с консолечкой - она не броситю
                                  >П.С. Просто съеби.
                                  Ответить
                                  • > П.С. Просто съеби.
                                    Просто съеби.
                                    Ответить
                                  • >>Слышал те же самые вещи из других источников.

                                    Слышал звон, да не знаешь где он.
                                    — Вот все говорят Битлы, Битлы а я послушал — так ничего особенного
                                    — Как же тебе удалось попасть к ним на концерт?!
                                    — Да что ты, мне просто знакомый напел...
                                    Ответить
                                    • >Слышал звон, да не знаешь где он.
                                      Уёбище, спрашиваю тебя в последний раз. Что там есть такого, что я не узнаю из других книг?
                                      Ответить
                        • >>SICP - это в основном про основы алгоритмов и структур данных. Слышал это из других источников.
                          Ответить
                  • Кстати, недавно познакомился с товарищем, переводившим книгу на русский, выразил ему свою глубокую благодарность. Внезапно мы оказались работающими в одной компании. Сейчас трудится над PFDS
                    https://github.com/gogabr/pfds
                    Ответить
    • Вспоминайте комбинаторику =)
      Ответить
    • (defun next-generation-change (so-far candidates tester)
        (loop for candidate in candidates
           if (funcall tester so-far candidate)
           collect (cons candidate (copy-list so-far))
           end))
      
      (defun at-goal-p (goal) (lambda (x) (= (reduce #'+ x) goal)))
      
      (defun before-goal-p (goal)
        (lambda (so-far candidate)
          (and (<= candidate (car so-far))
               (<= (reduce #'+ so-far) goal))))
      
      (defun breadth-first-make-change (total denominations)
        (loop with step-tester = (before-goal-p total)
           and goal-tester = (at-goal-p total)
           and generation = (mapcar #'list denominations)
           and result = nil
           while generation do
             (setf generation
                   (loop for candidate in generation
                      nconc (next-generation-change
                             candidate
                             denominations step-tester))
                   generation
                   (loop for candidate in generation
                      if (funcall goal-tester candidate) do
                        (push candidate result)
                      else collect candidate end))
           finally (return result)))

      Решение перебором "сначала вширь" :)
      Ответить
      • Антизеленый пост.
        Ответить
      • Слишком сложно!
        Ответить
        • Ну, можно было объединить создание следующего поколения с обнаружением целевых групп в одну функцию. Но в дидактических целях лучше оставить как есть: так легче понять что именно происходит.

          (defun next-gen-change (candidates denominations step-tester)
            (loop for candidate in denominations
               with total = (reduce #'+ candidates)
               and last = (car candidates)
               for next-action = (funcall step-tester total last candidate)
               if (eql next-action :continue)
               collect (cons candidate (copy-list candidates)) into gen
               else if (eql next-action :goal)
               collect (cons candidate (copy-list candidates)) into res end
               finally (return (values gen res))))
          
          (defun step-state (goal)
            (lambda (total last candidate)
              (cond
                ((and (<= candidate last) (< (+ candidate total) goal)) :continue)
                ((and (<= candidate last) (= (+ candidate total) goal)) :goal)
                (t nil))))
          
          (defun breadth-first-make-change (total denominations)
            (loop with step-tester = (step-state total)
               and result = nil
               for generation = (mapcar #'list denominations)
               then (loop for candidate in generation
                       nconc
                         (multiple-value-bind (gen res)
                             (next-gen-change
                              candidate denominations step-tester)
                           (setf result (nconc res result)) gen))
               while generation
               finally (return result)))

          Так, наверное, будет по-эффективнее, но и сложнее понять.
          Ответить
          • совершенно случайно возобновил чтение practical common lisp вчера. дочетал до (loop) и макросов. сверху - хорошая демонстрация темы почему народ на (loop) ругается. :)
            Ответить
            • Да код wvxvw вообще всегда отличная демонстрация того, почему народ ругается на common lisp ;)
              Ответить
            • Собственно, похожая проблема есть и в SQL - нет какого-то очевидного способа отформатировать код и практически нет знаков препинания.
              Но вместо цикла есть iterate, в котором с форматированием все нормально, и с ним бы тот же код читался лучше.
              Ответить
            • Да и кстати, ну я бы не сказал, что сверху такое что-то прямо из ряду вон выходящее, вот снизу - на такое имеет смысл ругаться. Рекурсивные макросы - это гарантированый взрыв мозга в отладчике. Такое можно только ради шутки сделать.
              Ответить
              • > Рекурсивные макросы
                Но зачем? Можно же наваять рекурсивную функцию, которая высрет нужное нам S выражение. А затем просто поюзать ее в макросе.
                Ответить
                • А почему кот яйца лижет?
                  ЗЫ. Вариант с рекурсивной функцией ничем не отличается кроме бесполезной функции засоряющей рантайм окружение. Проблема не в том как сделать, а в том, что то, что получается в итоге очень тяжело отлаживать, потому что исходного кода нигде нет, и бряк некуда поставить. Функция эту проблему не решит / не лучше чем макрос.
                  Ответить
                  • Так а макрос тоже останется валяться в рантайме. Куда он денется? Хорошо хоть GC запускается перед сохранением имиджа...

                    > Проблема не в том как сделать, а в том, что то, что получается в итоге очень тяжело отлаживать, потому что исходного кода нигде нет, и бряк некуда поставить.
                    Ну да, это основная проблема макроёбства почти на любом языке.

                    > Функция эту проблему не решит / не лучше чем макрос.
                    Согласен ;)
                    Ответить
                    • Макросов в рантайме не существует, по крайней мере стандарт не обязывает их хранить на время рантайма. В тех реализациях Лиспа, которые я пробовал, макросы не существуют в рантайме.
                      Ответить
                • and и or обычно рекурсивные
                  Ответить
                  • Только они не макросы... и отладчику о них известно достаточно, чтобы можно было спокойно работать. setf - да, типичный рекурсивный макрос, но в нетривиальных случаях со своими экспандерами можно на этом сильно обломаться.
                    Ответить
                    • > Только они не макросы
                      Зависит от диалекта
                      http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/and
                      Ответить
                      • Хм... что интересно, Hyperspec таки называет or макросом, но он практически всегда отдельно реализовывается. Почему-то я думал, что этот факт был узаконен, и or считается special operator, а вот нет...
                        В этом свете совершенно не понятно, почему if таки special operator, а or - нет.
                        Ответить
              • да. но в отличии от Перла, на Лисп почему то никто не ругается, пальцем не тыкает. абыдна панымаш.
                Ответить
                • Ну можно и поругаться ;)

                  multiple-value-bind - вот кто придумал такое название для часто используемой функции?
                  Ответить
        • Да, можно пойти еще дальше, и третьим значением возвращать только деноминации которые были использованы на данном этапе, и для следующего поколения убирать неиспользуемые - т.о. у нас будет меньше бесплодных попыток создать члена нового поколения. Но это уже упражнение для пытливого читателя.
          Ответить
          • Какие нахер поколения, какой перебор... Эта задачка вполне решается за O(m*n) сложений и O(n) памяти, где m - число видов монеток, n - сколько надо набрать...
            Ответить
            • Э... так я же не считаю сколько вариантов. Код выше генерирует комбинации монеток :)
              Ответить
              • Но задача то о подсчете была ;)
                Ответить
                • Задачу про подсчет давным давно решили - больше решать ее не интересно... Кроме того, а кто сказал, что говнокод.ру это бесплатная помощь в приготовлении домашнего задания?
                  Ответить
                  • Мозги разомните) Я вообще не знал что как бы решение в SICP есть, ну и набросал такой говнокодец -_-
                    Ответить
                    • (defun change-maker (amount denominations)
                        (labels ((%change-maker (amount coin)
                                   (cond ((= amount 0) 1)
                                         ((or (< coin 0) (< amount 0)) 0)
                                         (t (+ (%change-maker amount (1- coin))
                                               (%change-maker (- amount (nth coin denominations)) coin))))))
                          (%change-maker amount (1- (length denominations)))))

                      Ну вот, классическое решение, как в учебнике.
                      Ответить
                    • (defmacro looprec (denominations amount)
                        (let ((var (gensym "VAR")))
                          (if denominations
                              `(loop for ,var from 0 below (/ ,amount ,(car denominations))
                                  sum
                                    ,(macroexpand
                                      `(looprec ,(cdr denominations)
                                          ,(if (consp amount) (append amount `((* ,var ,(car denominations))))
                                               `(- ,amount (* ,var ,(car denominations))))))) 1)))

                      >или в общем случае (для произвольной суммы размера и набора монет).
                      но почему-то не сходится.
                      Ответить
                      • читал. много думал.

                        давно не видел такого макро-фу. наверное только в 90х, во времена асма, где были человеческие препроцессоры.
                        Ответить
                        • Хех, хоть кто-то оценил :)
                          А вообще, где такое "может" пригодится: например (хз как по-русски) binomial expansion посчитать не вычисляя все промежуточные степени. Т.е. сгенерировать что-то типа ((- (* n (expt x i)) (* (- m n) (expt x (+ n i))) ...) ...) и потом складывать коеффициенты (т.как часть отрицательные, то часть степеней не прийдется вычислять). А руками полиномы больше 5-6 степени просто замучаешься писать.
                          Ответить
                          • > Хех, хоть кто-то оценил :)

                            в мою защиту: с детства страдал слабостью к фракталам :)

                            > А вообще, где такое "может" пригодится

                            во всех тех местах где нужно ваять кучи кода, потому что на оптимизации типа constant propagation и inlining полагаться почти нельзя.

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

                            > binomial expansion

                            гугля говорит "биномиальное разложение"
                            Ответить
    • Негодую, почему еще нет примера на хаскеле, мода прошла?)
      main :: IO ()
      main = print $ combs [50,25,10,5,1] 100
      
      combs :: [Int] -> Int -> Int
      combs [1]    _ = 1
      combs (v:vs) s = sum $ map (combs vs) [s, s-v .. 0]
      Ответить
      • Не очень удачный способ, на самом деле. Для вывода вариантов такой перебор бы проканал, но вот для подсчета - производительность будет не айс.

        P.S. А вообще, после портянок на лиспе смотрится наглядно и понятно ;)
        Ответить
        • > Не очень удачный способ .. для подсчета
          Возможно, просто поискал в старой директории "project-euler" (а там надо лишь ответ) нашелся №31.
          Ответить
          • Порылся в одноименной директории, и выкопал там вот такую жуть:
            ways = foldl step (1 : repeat 0) where
                step list c = s where
                    (h, t) = splitAt c list
                    s = h ++ zipWith (+) t s
            
            main = print $ (ways [1,2,5,10,20,50,100,200] !! 200)
            Ответить
            • Поэффективнее спорить не буду, но вот читается с трудом).
              Ответить
              • > но вот читается с трудом
                Это факт, причем, имхо, из-за фолда ;) Сам то по себе алгоритм простецкий.
                Ответить
              • > но вот читается с трудом
                Хотя на четвертой странице форума по этой задаче есть вот такое чудо:
                v=.0:`1:`(1:`(([:}.@:])+(]:~[-{.@]))@.(1:<#@:]))@.(1:+*@[)
                Ответить

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