Ответы пользователя по тегу Алгоритмы
  • Почему не работает мой mergesort?

    @Mercury13
    Программист на «си с крестами» и не только
    int left[leftLen]

    Будь осторожен, на «боевых» задачах чревато переполнением стека. Стек вызовов невелик, всего ничего единицы мегабайт.
    Ответ написан
  • Как угадать возраст за наименьшее кол-во попыток?

    @Mercury13
    Программист на «си с крестами» и не только
    Бинарный поиск, однако точка деления — не (a+b)/2, а медиана куска распределения от a до b (т.е. round(F−1([F(a) + F(b)]/2)); F(·) — функция распределения, тупо переделанная из кусочно-постоянного вида в кусочно-линейный, сплайновый или ещё какой-нибудь).
    Немного неоптимально, но крайне просто.

    З.Ы. Эта штука достаточно оптимальна для «гладких» распределений. В общем случае неоптимальна — например, если у нас три возраста с вероятностями 0,45, 0,1 и 0,45, стоит спросить первый, потом третий и уж при полном невезении второй (среднее 1,65 запроса), а не брать среднее, а затем — первое или второе (в среднем 1,9 запросов).

    Если нужен точный оптимум — решать задачу динамического программирования по критерию
    N[a,b] = min{c} (1 + (N[a,c−1]p[a,c−1] + N[c+1,b]p[c+1,b]) / p[a,b]).
    Граничные условия: при a = b N[a,b] = 1; при a>b N[a,b] = 0.
    p[a,b] — суммарная вероятность от a до b включительно; вычисляется как sum[b]−sum[a−1]; sum[i] = sum{x <= i} p(x).
    N[0,M] = ?

    Или, обозначив Q[a,b] как N[a,b]p[a,b],
    Q[a,b] = min{c} (p[c] + Q[a,c−1] + Q[c+1,b]).
    Так как p[0,M] = 1, то Q[0,M] = N[0,M].
    Граничные условия: при a = b Q[a,b] = p[a]; при a>b Q[a,b] = 0.
    Q[0,M] = ?

    Решается задача за O(M²) операций. Если нужно хранить всю информацию, чтобы в нужный момент прокрутить цепь запросов — O(M²) памяти; если только указать оптимум — можно обойтись O(M).
    Ответ написан
    3 комментария
  • Как математически определить уникальное число для любых двух in64?

    @Mercury13
    Программист на «си с крестами» и не только
    Нельзя, простая комбинаторика.
    Одно число — 264 варианта, два числа — 2128 вариантов.
    Принцип Дирихле говорит, что в одной из клеток будут даже не два кролика, а как минимум ceil(2128/264) = 264 кролика — то есть для какого-то ответа будут как минимум 264 пары аргументов, которые его дают.
    Ответ написан
    3 комментария
  • Узко специализированно или широко?

    @Mercury13
    Программист на «си с крестами» и не только
    Это шаблон проектирования «стратегия», и по-хорошему реализуется в виде обработчиков или виртуальных функций.
    Ответ написан
    Комментировать
  • Алгоритмы: Задача о назначениях, как реализовать множественные назначения?

    @Mercury13
    Программист на «си с крестами» и не только
    Непонятно, как вы в такой ситуёвине считаете штраф. Ведь если штраф считается как раньше, а загрузка работника не ограничена, и задачи-то нет — каждую из работ можно дать тому работнику, который выполняет её лучше всех.

    Если же загрузка работника ограничена m работами — тогда решите задачу о максимальном потоке.

    Исток → работник: пропускная m
    работник → работа: пропускная 1
    работа → сток: пропускная 1
    Ответ написан
    Комментировать
  • Как дополнить топологическую сортировку?

    @Mercury13
    Программист на «си с крестами» и не только
    С двузначными метками посещения (bool used[]) — никак.

    Надо перейти на трёхзначные метки (UNVISITED, PARTLY_VISITED, VISITED).

    void dfs (int v) {
      state[v] = PARTLY_VISITED;
        .....
      state[v] = VISITED;
      ans.push_back (v);
    }


    Неплохой пример есть в вашем предыдущем вопросе.
    Ответ написан
    Комментировать
  • Как применить топологическую сортировку?

    @Mercury13
    Программист на «си с крестами» и не только
    Нужно переписать под матрицу смежности вот этот участок кода.
    for(int i = 0;i < Edges[v].size();i ++){
              if(dfs(Edges[v].get(i)))return true;
          }

    Что-то типа этого.
    цикл (i : все вершины)
       если матрица_смежности[v, i]
             если dfs(i)
                 return true;

    Ещё мне не нравятся константы 0, 1 и 2. Объявить бы их как
    UNVISITED = 0;
    PARTLY_VISITED = 1;
    VISITED = 2;

    Или WHITE, GRAY и BLACK, если хотите — в учебниках по алгоритмам их красят в три цвета.
    Ответ написан
    Комментировать
  • Как написать алгоритм спирали?

    @Mercury13
    Программист на «си с крестами» и не только
    688b4461d0a145be8f07116dcdad6612.png
    Ответ написан
    Комментировать
  • Как написать алгоритм спирали?

    @Mercury13
    Программист на «си с крестами» и не только
    И ещё одна штука. Две-семь точек надо располагать по-другому (одна в центре, остальные по кругу на расстоянии dSafe от неё; ну или на худой конец подобрать коэффициент a, чтобы спираль расходилась лишь чуть-чуть). Для восьми-одиннадцати точек надо подбирать индивидуальные a. И только для двенадцати и более подходит a = −0,3·dSafe.
    Ответ написан
    Комментировать
  • Как написать алгоритм спирали?

    @Mercury13
    Программист на «си с крестами» и не только
    Думаю, проще всего делать не спираль Архимеда, а её приближение методом Эйлера. Пусть у нас есть некое расстояние dSafe, на котором должны быть кружочки друг от друга.

    Чтобы поставить второй кружочек, отойдём от центрального на вектор (dSafe, 0). Для третьего и дальше поступим так.

    Найдём угол касательной к спирали Архимеда. Касательный вектор будет a единиц по радиус-вектору (a — коэффициент спирали r=aф) и r единиц по нормали. Таким образом, если мы в точке (x, y), у нас получается касательный вектор вот такой.
    t = (a·x + r·y; a·y − r·x), r = sqrt(x² + y²)

    Нормируем этот вектор до длины dSafe и добавляем к (x, y).
    Штука номер один. Параметр спирали прямо пропорционален безопасному расстоянию (вы это увидите ниже в коде). И штука номер два — только «бесконечно малые» шаги (при нулевом a, т. е. окружность) будут держать нас на окружности, шаги побольше будут выносить нас наружу, для компенсации сделаем a отрицательным.

    Вот действующий код (на C++ Builder’е)

    namespace {
    
    const double dSafe = 30;
    const int rSafe = dSafe / 2;
    const double a = -0.3 * dSafe;
    
    int toPixel(double x)
    {
        return floor(x + 0.5) + 200;
    }
    
    }
    
    void TfmMain::drawPoint(double x, double y)
    {
        int xx = toPixel(x);
        int yy = toPixel(y);
        Canvas->Ellipse(xx - rSafe, yy - rSafe, xx + rSafe, yy + rSafe);
    }
    
    void __fastcall TfmMain::FormPaint(TObject *Sender)
    {
        Canvas->Brush->Style = bsClear;
        Canvas->Pen->Color = clBlack;
    
        double x = 0, y = 0;
        drawPoint(x, y);
        x += dSafe;
        drawPoint(x, y);
    
        for (int i = 0; i < 120; ++i) {
            double r = sqrt(x*x + y*y);
            double tx = a*x + r*y;
            double ty = a*y - r*x;
            double tLen = sqrt(tx*tx + ty*ty);
            double k = dSafe / tLen;
            x += tx * k;
            y += ty * k;
            drawPoint(x, y);
        }
    }
    Ответ написан
    Комментировать
  • Алгоритм поиска кратчайшего пути в графе

    @Mercury13
    Программист на «си с крестами» и не только

    Если подвижных мостов мало, можно каждую вершину размножить в 2b экземплярах (b — кол-во мостов). Тогда пойдёт даже не Дейкстра, а обычный поиск в ширину.

    Если два моста «сцеплены» друг с другом и наводятся/разводятся одновременно, то в b они идут одной штукой.

    А если мостов много и 2b — непозволительная трата, тогда интересно. Думаю, ничего, кроме эвристик, не поможет. Например, может случиться так, что кратчайший путь от включателя до всех мостов, которыми он управляет, посуху. Или мосты (в смысле управляемые) — это мосты (в смысле теории графов). Или что-нибудь ещё.

    Ответ написан
    1 комментарий
  • Есть ли здесь бывшие олимпиадники? Как олимпиады помогли Вам?

    @Mercury13
    Программист на «си с крестами» и не только
    Скажу сразу, спортивного программирования у меня было не очень много: 10 класс — сборы (подвело незнание стандартной задачи на динамическое программирование, да и в одном месте надо было не Real применить, а Extended: проверяли шесть знаков, а у меня, при формально правильном алгоритме, было три или четыре). 11-й — по своей же глупости вообще не попал в призёры. В университете с командой как-то не заладилось, но это не мешало в одиночку быть второй ACM-«командой» факультета.

    Во-первых, олимпиада позволила мне попасть в университет на собеседование. Как я его проходил — отдельная история, но всё вышло как надо.

    Во-вторых, выработались некоторые приёмы малоглючного программирования. И сейчас посторонние мне часто говорят: «Ты код как на камне высекаешь».

    В третьих, алгоритмы есть алгоритмы. Всегда думаешь: а есть ли способ «наскоком» повысить скорость того или иного метода? Можно ли тут приплести, скажем, std::map?
    Ответ написан
    Комментировать