1. Java / Говнокод #12067

    +67

    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
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("Введите число:");
            String data = "";
            Integer x;
            try {
                data = in.readLine();
            } catch (IOException ex) {
                System.err.println(ex.getLocalizedMessage());
                return;
            }
            try {
                x = Integer.parseInt(data);
            } catch(NumberFormatException ex) {
                System.out.println("Вы ввели  не число!");
                return;
            }
            if(x <= 0) {
                System.out.println("Число должно быть положительным!");
                return;
            }
            HashMap friends_nums = new HashMap<Integer, Integer>();
            for(int i = 0; i <= x; i++) {
                int s = 0;
                for(int y = 1; y < i; y++) {
                    if(i % y == 0) { s += y; }
                }
                int t = 0;
                for(int y = 1; y < s; y++) {
                    if(s % y == 0) { t += y; }
                }
                if(t == i && s != i && !friends_nums.containsValue(i)) { friends_nums.put(i, s); }
            }
            if(friends_nums.isEmpty()) {
                System.out.println("Дружественных пар не найдено!");
            } else {
                System.out.println("Найдены следующие дружественные числа:");
                Object[] one = friends_nums.keySet().toArray();
                Object[] two = friends_nums.values().toArray();
                for(int i = 0; i<friends_nums.size(); i++) {
                    System.out.println(one[i] + " и " + two[i]);
                }
            }
        }

    Дружественными числами называются два различных натуральных числа, для которых сумма всех собственных делителей первого числа (сумма всех делителей, отличных от самого числа) равна второму числу и сумма всех собственных делителей второго числа равна первому числу. Примеры дружественных чисел: 220 и 284. Делители числа 220: 1, 2, 4, 5, 10, 11, 20, 22, 44, 55, 110 (в сумме дают число 284); делители числа 284: 1, 2, 4, 71, 142 (в сумме 220). Примеры других пар дружественных чисел: 2620 и 2924, 17296 и 18416. Написать программу, которая по заданному натуральному числу N находит все пары дружественных чисел, не превосходящих N.

    Запостил: JavaCoder, 06 Ноября 2012

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

    • > строки 1-16
      Чтение целого числа давно пора оформить в функцию. В других лабах тоже пригодится.

      > for(int y = 1; y < i; y++) {
      Искать делители делением по самое число... как бы мягко выразиться... некрасиво. Но для мелких чисел как в задаче - конечно пофиг. Вычисление суммы делителей числа стоит вынести в функцию.

      > !friends_nums.containsValue(i)
      Чтобы убить одинаковые пары достаточно было тупого сравнения i<s или i>s. Хешмап это оверкилл. Да еще и заставили бедного хешмапа заниматься неподобающей ему операцией - проверкой того, что он содержит заданное значение.
      Ответить
      • >Чтение целого числа давно пора оформить в функцию. В других лабах тоже пригодится.
        И так потихоньку у тебя вырастает самописная библиотека для упрощения и обхода говен в стандартной библиотеке.

        >Хешмап это оверкилл
        Вот и выросло поколение, которое не уважает бит массивы.
        Ответить
        • вы уделяете слишком много внимания чуваку, который ухитрился написать, цитирую:
          > .keySet().toArray()
          > .values().toArray()
          Ответить
          • > .keySet().toArray()
            > .values().toArray()
            Что не сделаешь, чтобы не читать документацию.
            Ответить
        • > Вот и выросло поколение, которое не уважает бит массивы.
          Эм, это обо мне? ;(
          Ответить
    • расцениваю данный школокод как спам
      Ответить
      • Расцениваю данный комментарий как истину.
        Ответить
    • JavaGovno...
      Ответить
    • divisors n = [x | x <- [1..(n `div` 2)], mod n x == 0]
      isFriendTo x y = x == (sum $ divisors y)
      isFriends x y = x `isFriendTo` y && y `isFriendTo` x
      Ответить
      • areFriends
        or
        isFriendsWith
        Ответить
        • isFriend = not isEnemy && not isNeutral
          Ответить
          • У тебя же сейчас ночь? Имхо хаскель вредно читать. Я после того как его начал читать - тоже перестал спать по ночам.
            Ответить
            • Я вообще красноглазый, мне не привыкать.
              Ответить
      • К слову об удобстве бесконечных списков: http://ideone.com/uuUS1q.

        А то введите число, введите число...
        Ответить
        • А если поступать не как автор исходного ГК, а так, как я написал в первом своем комменте - то ideone успевает посчитать аж 14 таких пар.

          http://ideone.com/m656Ec
          Ответить
          • Выжал всё что мог из кода на C++, всё равно получилось медленнее, чем на хаскелле оО.

            пруф:
            http://ideone.com/6XwxCw
            Ответить
            • Я считаю делители до корня, а вы до половины. Отсюда и разница.

              http://ideone.com/mcPaDf

              P.S. Си все таки быстрее хаскеля ;)
              Ответить
              • Как и ожидалось в 3 раза:
                http://ideone.com/hLrgiR
                Ответить
              • Я считал не до половины.

                for ( int d = 2; d < upperLimit; ++d )
                upperLimit = (x / d);


                Так-что в итоге это до корня. Сразу до корня я не додумался.
                Ответить
                • >result += (x / d);
                  >upperLimit = (x / d);
                  Тоже кал, хоть в этом есть зачатки правильной идеи. Или компилер такое нынче хавает?

                  Я бы еще попробовал разложить на степеня простых чисел и потом искать сочетания.
                  Но лень.
                  Ответить
                  • Факторизация числа конечно быстрее, но вот как потом взять собственные множители из факторов...
                    Ответить
                    • я бы просто стал гуглить эффективный алгоритм по "Amicable numbers"
                      Ответить
                    • Уникальные сочетания степеней.
                      Например довольное большое число:
                      2^3*3^4*11^2
                      i=2 for [0..3]
                      j=3 for [0..4]
                      k=11 for [0..2]
                      for each (s=i*j*k)
                      sum+=s;
                      Всего-то собрать 4*5*3=60 сумм.
                      Ответить
                  • Запилил с разложением:
                    http://ideone.com/L0iWpQ

                    Тормозной хаскель снова порвал сишечку по производительности.

                    P.S. Лишнее подтверждение того, что алгоритм важнее микрооптимизаций.
                    Ответить
                    • http://ideone.com/NrFF2E
                      Очевидно фикс до поры до времени. Теперь в 2 раза больше порвал.
                      Ответить
                      • А в чем разница? Что в джва раза?
                        >хаскель снова порвал сишечку по производительности.
                        И вообще не провоцируйте меня.
                        Ответить
                        • >А в чем разница? Что в джва раза?
                          Integer (BigInteger) => Int

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

                          Сикодеры нервно курят в сторонке перед надёжным хаскеллом
                          Ответить
                    • Меня вот это if p*p > n по прежнему смущает.
                      Ответить
                      • См. эксперимент ниже http://govnokod.ru/12067#comment159275.

                        Походу sqrt настолько тормозной, что десяток-другой умножений спокойно его обгоняет.
                        Ответить
                    • Кстати, как я посмотрю тут можно запилить более эффективную функцию primes и получить ещё больший прирост.
                      Ответить
              • > d*d <= x
                Фу.
                Ответить
                • >> d*d <= x
                  > Фу.

                  Надо d <= sqrt(x)?
                  Ответить
                  • Нет конечно.
                    int upper=sqrt(x)+1;

                    while(d <= upper)
                    Ответить
                    • А делить/умножать на два сдвигом?
                      Ответить
                      • Причем тут "делить/умножать на два сдвигом?".
                        Поясните мысль.
                        Это корень.

                        Насчет бинарной арифметики и сдвигов - пост ниже.

                        Там просто надо найти позицию младшей единицы, сдвинуть число, убрав всё младшие нули.
                        Потом пройтись по нечетным до корня (уже нечетного числа) и сложить.
                        После чего умножить на чудесный коэфициент.
                        Ответить
                      • exp( (int)log(x) >> 1 )
                        Ответить
                    • http://ideone.com/e7WVG4
                      http://ideone.com/uqIpBU

                      Для 35 пар, собиралось с O2:
                      $ time ./sqrt >/dev/null
                      real	0m1.766s
                      user	0m1.760s
                      sys	0m0.000s
                      $ time ./mul >/dev/null
                      real	0m1.749s
                      user	0m1.740s
                      sys	0m0.004s


                      Так что где еще фу.
                      Ответить
                      • Так 3.74s это меньше чем 3.79s. Ну то есть приведенные Вами ссылки на ideone подтвержают мою правоту.
                        http://ideone.com/mcPaDf //fai 0.54
                        http://ideone.com/nmdGc7//me 0.53
                        Ответить
                        • Для 35 пар у sqrt результат хуже
                          Ответить
                        • Ну один фиг копеечная микрооптимизация.

                          Имхо стоит асимптотику оптимизнуть в алгоритме с разложением, а не задрачивать корни и сдвиги вместо делений...
                          Ответить
                          • Когда там будет нормальный алгоритм типа этого:
                            http://govnokod.ru/12067#comment159249
                            http://govnokod.ru/12067#comment159266

                            цена оптимизации выростет.
                            Ответить
                          • >асимптотику оптимизнуть в алгоритме с разложением
                            Ну это проще простого, правда хацкель мне даже читать трудновато.
                            А писать своё лень.
                            Ответить
                            • Упростил код с разложением. Это будет последняя версия до тех пор, пока кто-нибудь не обгонит ее. 37 пар / 4.45s.
                              http://ideone.com/pBmRP3

                              > нормальный алгоритм типа этого
                              Ну так разложение что-то типа этого и есть. Считаем сколько раз c[i] встречается каждый из простых множителей p[i]. Затем применяем простенькую формулку product(1+p[i]...+p[i]^c[i]) и вычитаем из нее само число (т.к. его не считают своим же делителем).
                              Ответить
                              • >Это будет последняя версия до тех пор, пока кто-нибудь не обгонит ее. 37 пар / 4.45s.

                                http://ideone.com/mN3tO7

                                Ололо. Я тебя обогнал ничго не делая: 37 пар / 1.76s
                                Ответить
                                • http://ideone.com/whrOpQ

                                  37 / 4.3
                                  Ответить
                                • Читер. Ну раз уж читерить так по полной.

                                  Ну его нахуй этот хаскель, пойду на крестах напишу.

                                  30 пар:http://ideone.com/kyLGMK
                                  60 пар:http://ideone.com/mIoEKj

                                  P.S. Интересно до скольки мог досчитать исходный алгоритм ОП'а за час ;)
                                  Ответить
                                  • Нет читерству. Только длинные числа, только хардкор.
                                    Ответить
                                  • Код к слову неправильный.

                                    Не нашёл пару (1184,1210)
                                    Ответить
                                    • > Код к слову неправильный.
                                      http://ideone.com/dhYoqD
                                      fxd.

                                      Досадный баг.
                                      Ответить
                              • Кстати, так я подозреваю, что есть момент с замедлением, из-за факторизации больших чисел из малого количества множителей.

                                Если найти более эффективный алгоритм факторизации, можно будет значительно ускорить алгоритм.
                                Ответить
                                • Как вариант - можно попробовать не разбивать числа на множители, а строить их. При этом смотреть не то, что сумма делителей одного числа, не включая его, дает другое и наоборот, а более простое но равносильное правило - сумма всех делителей одного числа (включая его самого) равна сумме всех делителей второго...
                                  Ответить
            • >Выжал всё что мог из кода на C++
              > всё равно получилось медленнее, чем на хаскелле оО.
              Стыдоба ебучая.
              Ну ведь говно полное. Надо головой думать, например - искать количество делителей степени 2 - n, потом идти по нечетным до корня от деления на 2^n.
              Ну и потом умножать примерно на 2^(n)-1.

              А потом вот такие вот люди делают бенчи в которых жаба быстрей си, сисярп.assParallel() быстрее ассемблера, а хацкель быстрей плюсов.
              Ответить
              • Я не делаю бенчи.

                "Выжал всё что мог из кода на C++" - не значит, что я написал эффективный алгоритм.

                Напишите версию быстрее чем текущая (http://ideone.com/mcPaDf), раз уж код такое говно.
                Ответить
                • Напишите версию быстрее чем текущая
                  запросто:
                  http://ideone.com/nmdGc7
                  0.53 ms
                  Ответить
                • Инфа устарела. Самая быстрая версия http://govnokod.ru/12067#comment159272.

                  P.S. Если прога на Си позиционируется как "быстрая" и не рвет прогу на хаскеле раз в 10 - то эта сишная прога говно. Я более чем уверен, что на си алгоритм с факторизацией отрабатывал бы на порядок быстрее чем на хаскеле.
                  Ответить
                  • Она была бы в n раз быстрее и в n раз больше.
                    Ответить
    • Просто нужно было очень быстро решить поставленную задачу. Забыл сразу добавить, что да, очень корявенько. Самый натуральный говнокод. Главное, что оно работает.
      Ответить
    • Из кoлeи выбилo кaпитaльнo и, приeхaв нa aвтoбусe oбрaтнo в Oзёры, купил в мaгaзинe вoдки, нaпился дoмa, в oднo лицo, дo свинскoгo сoстoяния.
      Ответить

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