Блог пользователя freopen

Автор freopen, 14 лет назад, По-русски
Посоветуйте, где можно про него прочитать? Я читал вот тут: http://e-maxx.ru/algo/matching_edmonds, а потом решал задачу 1099 с тимуса, но она заTLилиась. Мой код практически идентичен e-maxxовскому. Кстати, вот код. Заранее спасибо за помощь.
  • Проголосовать: нравится
  • -3
  • Проголосовать: не нравится

14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Странно, что заTLилось, в этой задаче мгновенно проходит абсолютно тупой Эдмондс за O(n^4), если сначала жадно инициализировать паросочетание. Попробуйте добавить эту оптимизацию, посмотрим, какое получится время.
  • 14 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    ну у меня Эдмондс за n^3, причем с жадной инициализацией. Без нее TL6. С ней - TL12. Кстати, как пишется Эдмондс за n^4?
    • 14 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      За n^4 пишется абсолютно прямолинейно - если нашли нечётный цикл, то совершенно тупо его сжимаем, пересчитывая новую матрицу смежности графа. Я так делал (причём матрицу смежности хранил как vector< vector<int> >), у меня там за 0.046 прошло (правда, это было несколько лет назад, может, у них сервера стали медленнее? :)). Попробуйте локально запустить на макстесте, посмотрите, сколько работает. Если действительно >TL, то скомпилируйте с профилировкой (g++ -O2 prog.cpp -pg), запустите программу, после этого посмотрите, что скажет профилировщик (gprof prog.cpp). Там будет показано, что в программе сколько времени работало, и можно понять, где bottleneck. Это может помочь в понимании того, в чём проблема.
14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
попробуйте вектора заменить на массивы. они дают немаленькую константу.
  • 14 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Ну там и так все, что можно заменено. А хранить сам граф по другому - немного выиграю
    • 14 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      боюсь, вы меня не поняли))

      int e[230][230];
      int e_sz[230]; // размер

      работает раз 5-10 быстрее, чем

      vector<int> e[230];
      • 14 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        ну исправил. Все равно TL12
        • 14 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          значит баг в реализации - что-то где-то заходит в бесконечный цикл. n^3 без stl в любом случае пролезет.
14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
На этой задаче отлично проходит код схожий с e-maxовским... (по нему читал алгоритм, и после сдавал).
  • 14 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Я, наверное, непонятно написал... Я и написал код, схожий с e-maxxовским. Практически один в один совпадает. Вот только TL12
    • 14 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Ну раз почти один в один совпадает, то можно в начале сдать алгоритм с e-maxx, а затем маленькие куски кода менять на свою реализацию и сдавать. Как только затлит - будет известно место, где баг.
      • 14 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        кхм. Я наверно и второй раз плохо объяснил. Мой код практически полностью совпадает с e-maxx. В нем нет моих кусков кода.
        • 14 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          Обычно, если пишут "практически полностью совпадает", то имеют ввиду что процент совпадения очень велик, но не равен 100%. Я когда-то тоже читал этот алгоритм на e-maxx, потом написал его и сдал эту задачу на Тимусе, причем работало оно довольно быстро (0.015 секунд).
          • 14 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится
            Не равен. В частности я добавил ввод-вывод, а также переименовал некоторые массивы. Еще я исправил пару очень маленьких мест которые уже полностью исследовал. Ну не может оттуда взяться TL.
            • 14 лет назад, # ^ |
                Проголосовать: нравится 0 Проголосовать: не нравится
              Так, а там не бывает кратных рёбер? Они бы объяснили ваш TL - алгоритм работал бы дольше, не говоря о чтении cin'ом неопределённо большого количества данных.
              • 14 лет назад, # ^ |
                  Проголосовать: нравится 0 Проголосовать: не нравится
                Исправил кратные ребра и заменил cin на scanf. Но все равно TL12
                • 14 лет назад, # ^ |
                    Проголосовать: нравится 0 Проголосовать: не нравится
                  В таком случае я бы посоветовал просто попробовать изменить те исправленные места, откуда не может взяться ТЛ, обратно и сдать. А лучше просто скопировать с сайта и сдать, чтобы исключить возможность ошибки. Если уже полностью скопированный (только с добавленным вводом и выводом) алгоритм будет ТЛить, то можно уже искать баги на сайте. Если же нет - надо искать у себя.
14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Иногда помогает стереть весь код и написать полностью заново.
  • 14 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Да но не когда переписал почти весь код с другого сайта
14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Может, и правда бага?.. Первые мои варианты реализации действительно страдали зависаниями... Правда этот, последний, выдержал длинный стресс-тест, но всё равно это, конечно, не доказательство.
  • 14 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Говорят, кто-то твой код умудрился сдать. Но у меня так и не вышло...
    • 14 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      Как я понял, Kenny_HORROR всё же реализовывал самостоятельно, так что вероятность баги у меня ненулевая.


      Сейчас снова попробую стресс устроить.

      • 14 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        Самое непонятное в твоей реализации место - в функции mark_path. Непонятно, почему ты не переходишь сразу на базу текущего цветка. А красишь при этом только базы
        • 14 лет назад, # ^ |
            Проголосовать: нравится +12 Проголосовать: не нравится

          Да, красятся только базы, но что такое база? Это сжатый номер вершины. Ну здесь прямо напрашивается аналогия с DSU: мы красим не сам элемент, а всё множество целиком, для чего надо покрасить только представителя этого множества, а потом при проверке "покрашенности" смотреть всегда только на представителя (в нашем случае всегда пишется "if (blossom[base[i]])").


          База base[v] на момент входа в функцию - это пока не база обнаруженного цветка, это сжатый номер вершины в DSU. Задача этой функции - в том, чтобы пройтись от текущей вершины до корня обнаруженного цветка, и для каждой нечётной вершины проставить предка p[]. Этот процесс лучше по бумажке понять (в статью бы тоже было бы круто вставить картинку, но у меня большая лень на картинки, как можно заметить по всему сайту :))) ). Ещё раз, суть в том, что обход в ширину проставляет p[] только для вторых концов рёбер паросочетания; функция же mark_path проставляет p[] для первых концов паросочетания, но в обратную сторону. Т.е. если предки, проставленные обходом в ширину, ведут "вверх" по дереву обхода, то предки, доставленные mark_path'ом, ведут обратно "вниз".


          Это и правда очень хитрый момент алгоритма, самый вынос мозга :) Такая хрень с предками нужна, чтобы по предкам всегда можно было дойти до корня цветка, встав в любую точку цветка. Ведь обход в ширину даёт информацию о предках только для чётных вершин (вторых концов рёбер парсоча); предки же из нечётных вершин должны вести по циклу в противоположную сторону, иначе мы из нечётной вершины ну никак не придём чередующимся путём в корень цветка.


          Вот :) Несколько сумбурно, но может, чуть лучше, чем в статье написано.

          • 14 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится
            Да, но ведь если вершина имеет базу, то есть принадлежит цветку, то ребра из нечетных вершин уже проставлены. Тогда же, когда мы заменили базу для этих вершин. Разве нет?
            • 14 лет назад, # ^ |
                Проголосовать: нравится 0 Проголосовать: не нравится

              Вершина всегда имеет базу, только до всяких цветков база указывает на саму же вершину.

              mark_path проставляет предков до того, как мы все вершины цветка сожмём в одну, он работает со старыми базами.

              • 14 лет назад, # ^ |
                  Проголосовать: нравится 0 Проголосовать: не нравится
                Я уже догадался. Просто я думал, что массив blossom говорит нам, у каких вершин надо поменять базу. А оказалось, что у вершин с какой базой надо поменять базу. В этом и был глюк.
      • 14 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        Да помоему, там всё ок с кодом... Я у себя баги по нему искал. =)
14 лет назад, # |
  Проголосовать: нравится +12 Проголосовать: не нравится
Хм. У меня копипаст с сайта прошёл за 31 мс... :)
  • 14 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    А можно на твой код взглянуть целиком?
    • 14 лет назад, # ^ |
        Проголосовать: нравится +1 Проголосовать: не нравится
      http://pastebin.com/unybQz4k
      • 14 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        Благодарю, нашел ошибку. Была как раз в том, что я проверял на принадлежность цветку вершину, а надо было базу. Заодно теперь понятно, почему это правильно :)
14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Хочу заметить, что изначально вопрос звучал по другому. Я спрашивал, где можно почитать про сжатие цветков кроме как у e-maxxа?
  • 14 лет назад, # ^ |
      Проголосовать: нравится +1 Проголосовать: не нравится

    Кристофидес "Теория графов"

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

14 лет назад, # |
  Проголосовать: нравится +1 Проголосовать: не нравится

Вообще по-моему алгоритм Эдмондса очень красивый, мне нравится это элегантный перенос алгоритма Куна на произвольные графы. Имхо один из самых красивых алгоритмов.

Жаль только, что с реализацией большие сложности возникают...