Пузырьки каких-то условий без использования структуры? - PullRequest
0 голосов
/ 21 февраля 2019

Есть турнир.Игроки идентифицируются целыми числами и играют в турнирном стиле с целым рядом с ними.Итак, 1 играет 2, 3 играет 4, 5 играет 6, 7 играет 8. Затем 1/2 играет 3/4, 5/6 играет 7/8, а затем 1/2/3/4 играет 5/6 /7/8.

Пример ввода:

8 5
1 2 3 4 5

Первая строка = первая цифра - количество игроков в турнире (всегда около 2 ^ N), вторая цифра - количество игроков, которые вышли дотурнир начался

Вторая строка = идентификаторы игроков, которые сняли

Если игрок автоматически переходит в следующий раунд, потому что человек, которого он бы сыграл, вышел из игры (назовите это BYE)увеличить счетчик.Выведите счет в конце.

Таким образом, выходной сигнал для выборки будет равен 2 (6 автоматически продвигаются в первом раунде, потому что 6 должно было сыграть 5, кто ушел, и в конечном итоге в предпоследнем раундераунд, 6/7/8 автоматически продвигается).

Я думал либо о том, чтобы держать все в дереве (но это было бы неэффективно, не так ли?), либо просто разбирать на ходу и пузыритьсядо свидания.Проблема с этим вторым решением заключается в том, что я понятия не имею, как рассматривать / хранить отношения с точки зрения того, кто, с кем будет играть, и как именно вы реализуете что-то без структуры.

Ответы [ 3 ]

0 голосов
/ 21 февраля 2019

Вы можете обойтись простым массивом (размером 2 ^ N).Закодируйте своих участников как 0 для отсутствующих и 1 для настоящих, и смоделируйте турнир.В каждом раунде игрок с индексом 2*k играет с индексом 2*k + 1, и «победитель» перемещается на индекс k.Пока условие XOR, а «победитель» - ИЛИ.В псевдокоде

    while player_count > 1
        for k in range (player_count / 2)
            byes += arr[2*k] ^ arr[2*k + 1]
            arr[k] = arr[2*k] | arr[2*k + 1]
        player_count /= 2

Пространство и время линейны по числу игроков.

0 голосов
/ 22 февраля 2019

Вот решение по времени O(R log R) и пробелу O(R), где R - количество выбывших (снятых) игроков.Если вышедшим на пенсию игрокам дается в порядке возрастания идентификатора, то ваше последнее понимание правильное: вы можете просто прочитать идентификаторы и вспомнить их во времени O(R) и O(1) памяти.Это помогает, когда N намного больше, чем R (например, миллиарды), потому что это исключает сохранение любого массива размером N.

Концептуально идентификаторы вышедших на пенсию игроков - это листья в дереве.Вот дерево для N = 8. Я вычел 1 из всех идентификаторов, потому что это оказалось проблемой взлома, и хакеры любят считать от 0.: -)

           0-7
        /       \
     0-3         4-7
   /     \     /     \
 0-1    2-3   4-5    6-7
 / \    / \   / \    / \
0   1  2   3 4   5  6   7

Идея состоит в том, чтобыпосмотрите на компактные диапазоны во входных данных и выясните, сколько байсов они дают.Например, диапазон [0-3] дает один пока: ни одной игры в левой скобке (поддереве) не ведется, и тот, кто достигает финала из диапазона [4-7], получает прощание в финале.То же самое касается диапазона [4-7].По сути, если один диапазон покрывает одно полное поддерево, это один пока.Обратите внимание, что мы ищем максимально полные поддеревья, например, [0-3], а не [0-1] + [2-3] отдельно.

Как насчет [0-4]?Нам нужно разделить диапазон на [0-3] и [4-4].Тогда [4-4] является вторым поддеревом (тривиальным с одним узлом), то есть игрок 5 также получит прощай.Таким образом, [0-4] считается как два байса.Мы определяем это путем подсчета битов в количестве 5 (размер диапазона).Так как 5 = 101 2 , мы получаем ответ 2. Это часть битового взлома, которую я замаскирую, но могу расширить при необходимости.

Последний вопрос, который нужно рассмотреть, - ограничениеразмер диапазона.Пусть N=1024 и рассмотрим диапазон [4-100].Начиная с 4, поддерево заполняется до 7, и в этот момент мы должны обработать диапазон [4-7] (и получить 1 пока), а затем продолжить с 8 (это поддерево, в свою очередь, заполнится на 15 и т. Д.).Вычисление правильного конца также включает в себя немного взломать.Рассмотрим начальную точку 40 = 101000 2 .Размер поддерева задается младшим значащим битом, а именно 1000 2 = 8, поэтому мы должны пробиться после диапазона [40-47].Опять же, я замаскирую детали, но могу расширить при необходимости.

Код на C оказывается довольно коротким (извинения за то, что я не писал на Java, это было давно).Для краткости он подсчитывает биты с помощью встроенной функции *1029* в GCC, но есть множество других доступных методов.Аналогично, ограничение размера диапазона включает нахождение самого правого установленного бита .

#include <stdio.h>

void startRange(unsigned p, unsigned* start, unsigned* end, unsigned* limit) {
  *start = *end = p;
  *limit = p + (p & -p) - 1;
  printf("started range %u limit %u\n", p, *limit);
}

int processRange(unsigned start, unsigned end) {
  printf("processing range [%u,%u]\n", start, end);
  return __builtin_popcount(end - start + 1);
}

int main() {
  unsigned n, r, p, result;
  unsigned start, end, limit;

  /* read from standard input */
  scanf("%d%d%d", &n, &r, &p);
  startRange(p - 1, &start, &end, &limit);
  result = 0;

  while (--r) { /* read r-1 more numbers */
    scanf("%d", &p);
    p--;

    if (p == end + 1 && p <= limit) {
      /* continue while we have consecutive numbers, but not past the limit */
      end++;
    } else {
      /* close the previous range and start a new one at p */
      result += processRange(start, end);
      startRange(p, &start, &end, &limit);
    }
  }

  /* close any outstanding range we have */
  result += processRange(start, end);
  printf("%d\n", result);

  return 0;
}
0 голосов
/ 21 февраля 2019

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

Вот пример рекурсивного решения:

public class App {
    public static void main(String[] args) {
        // I use 0 based indexing here
        Set<Integer> absent = new HashSet<>(Arrays.asList(0, 1, 2, 3, 4));

        int count = rec(absent, 8, 0);
        System.out.println("count = " + count);
    }

    private static int rec(Set<Integer> absent, int currentGroupSize, int start) {
        if (currentGroupSize == 1) {
            return absent.contains(start) ? -1 : 0;
        }

        int r1 = rec(absent, currentGroupSize / 2, start);
        int r2 = rec(absent, currentGroupSize / 2, start + currentGroupSize / 2);
        if (r1 == -1) {
            if (r2 == -1) {
                return -1;
            } else {
                return r2 + 1;
            }
        } else {
            if (r2 == -1) {
                return r1 + 1;
            } else {
                return r1 + r2;
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...