EduBrick

Функция Гранди

Позиции мало приписать «выигрышная или проигрышная»: чтобы складывать игры, нужно число. Это число — mex по достижимым позициям.

3 мин

Булева пометка «выигрышная или проигрышная» отвечает на вопрос про одну игру. Но если играют сразу в несколько независимых игр и ход — сходить в любой из них, знания исходов по отдельности не хватает: две проигрышные игры вместе могут оказаться выигрышными, а могут и нет.

Чтобы игры можно было складывать, позиции приписывают число — значение Гранди:

G(v)=mex{G(u):u достижима из v за один ход},G(v) = \mathrm{mex}\,\{\,G(u) : u \text{ достижима из } v \text{ за один ход}\,\},

где mex\mathrm{mex} множества — наименьшее неотрицательное число, которого в нём нет. У позиции без ходов множество пусто, и mex=0\mathrm{mex}\,\varnothing = 0.

Связь с исходом

Позиция проигрышная тогда и только тогда, когда G=0G = 0.

Обе стороны следуют прямо из mex\mathrm{mex}:

  • если G(v)=0G(v) = 0, то нуля среди значений соседей нет — все ходы ведут в выигрышные позиции;
  • если G(v)=k>0G(v) = k > 0, то все числа 0,,k10, \dots, k-1 среди соседей есть, в частности ноль, — есть ход в проигрышную.

То есть для одной игры Гранди не даёт ничего нового. Всё богатство — в сумме игр.

Как считать

int grundy(int v) {
    if (computed[v]) return value[v];
    computed[v] = true;
    std::vector<char> seen(moves[v].size() + 1, 0);
    for (int u : moves[v]) { int g = grundy(u); if (g < (int)seen.size()) seen[g] = 1; }
    int m = 0;
    while (m < (int)seen.size() && seen[m]) m++;
    return value[v] = m;
}

Размер seen выбран не случайно. Значение mex\mathrm{mex} по dd числам не превосходит dd, поэтому массива длины d+1d + 1 хватает всегда, а всё, что больше, можно не запоминать. Суммарно по всем вершинам это O(V+E)O(V + E) — без этого приёма получилось бы O(VmaxG)O(V \cdot \max G) памяти или лишний логарифм на множество.

Кратные рёбра значение не меняют. mex\mathrm{mex} считается по множеству, а повтор в множестве ничего не добавляет. Но время они съедают, так что при mm рёбрах цикл всё равно проходит все mm штук.

Чему равно значение Гранди

Заранее — ничему. Для конкретной игры его считают перебором на маленьких размерах, после чего смотрят на таблицу и угадывают закономерность; см. «Как искать закономерность».

Пара примеров, чтобы было с чем сравнивать:

игра значение Гранди
куча xx, берут сколько угодно xx
куча xx, берут от 1 до kk xmod(k+1)x \bmod (k + 1)
куча xx, берут элемент из SS периодично, период ищется перебором

Смежное

  • Сумма игр — зачем всё это было;
  • Ним — игра, ради которой определение и придумано.