ЗАДАЧИ
problems.ru |
О проекте
|
Об авторах
|
Справочник
Каталог по темам | по источникам | |
|
Задача 98834
УсловиеПеречислить все последовательности длины n из чисел 1..k в таком порядке, чтобы каждая следующая отличалась от предыдущей в единственной цифре, причём не более, чем на 1.РешениеРассмотрим прямоугольную доску ширины n и высоты k. На каждой вертикали будет стоять шашка. Таким образом, положения шашек соответствуют последовательностям из чисел 1..k длины n (s-ый член последовательности соответствует высоте шашки на s-ой вертикали). На каждой шашке нарисуем стрелочку, которая может быть направлена вверх или вниз. Вначале все шашки поставим на нижнюю горизонталь стрелочкой вверх. Далее двигаем шашки по такому правилу: найдя самую правую шашку, которую можно подвинуть в направлении (нарисованной на ней) стрелки, двигаем её на одну клетку в этом направлении, а все стоящие правее неё шашки (они упёрлись в край) разворачиваем кругом. Ясно, что на каждом шаге только одна шашка сдвигается, --е один член последовательности меняется на 1. Докажем индукцией по n, что проходятся все последовательности из чисел 1..k. Случай n=1 очевиден. Пусть n>1. Все ходы поделим на те, где двигается последняя шашка, и те, где двигается не последняя. Во втором случае последняя шашка стоит у стены, и мы её поворачиваем, так что за каждым ходом второго типа следует k-1 ходов первого типа, за время которых последняя шашка побывает во всех клетках. Если мы теперь забудем о последней шашке, то движения первых n-1 по предположению индукции пробегают все последовательности длины n-1 по одному разу; движения же последней шашки из каждой последовательности длины n-1 делают k последовательностей длины n. В программе, помимо последовательности x[1]..x[n], будем хранить массив d[1]..d[n] из чисел +1 и -1 (+1 соответствует стрелке вверх, -1 — стрелке вниз). Начальное состояние: x[1]=...=x[n]=1; d[1]=...=d[n]=1. Приведём алгоритм перехода к следующей последовательности (одновременно выясняется, возможен ли переход — ответ становится значением булевской переменной p).{если можно, сделать шаг и положить p := true, если нет, положить p := false } i := n; while (i > 1) and | (((d[i]=1) and (x[i]=n)) or ((d[i]=-1) and (x[i]=1))) | do begin | i:=i-1; end; if (d[i]=1 and x[i]=n) or (d[i]=-1 and x[i]=1) then begin | p:=false; end else begin | p:=true; | x[i] := x[i] + d[i]; | for j := i+1 to n do begin | | d[j] := - d[j]; | end; end; Замечание. Для последовательностей нулей и единиц возможно другое решение, использующее двоичную систему. (Именно оно связывается обычно с названием " коды Грея".) Запишем подряд все числа от 0 до 2n - 1 в двоичной системе. Например, для n = 3 напишем:
000 001 010 011 100 101 110 111
Затем каждое из чисел подвергнем преобразованию, заменив
каждую цифру, кроме первой, на её сумму с предыдущей цифрой
(по модулю 2). Иными словами, число
a1, a2,..., an
преобразуем в
1mua1, a1 + a2, a2 + a3,..., an - 1 + an (сумма по модулю 2). Для n = 3 получим:
000 001 011 010 110 111 101 100
Легко проверить, что описанное преобразование чисел
обратимо (и тем самым даёт все последовательности по одному
разу). Кроме того, двоичные записи соседних чисел
отличаются заменой конца
011...1 на конец
100...0,
что — после преобразования — приводит к изменению
единственной цифры.
Источники и прецеденты использования |
© 2004-...
МЦНМО
(о копирайте)
|
Пишите нам
|