ЗАДАЧИ
problems.ru |
О проекте
|
Об авторах
|
Справочник
Каталог по темам | по источникам | |
|
Задача 98825
УсловиеДля заданных n и k (РешениеБудем представлять каждое подмножество последовательностью x[1]..x[n] нулей и единиц длины n, в которой ровно k единиц. (Другой способ представления разберём позже.) Такие последовательности упорядочим лексикографически (см. выше). Очевидный способ решения задачи — перебирать все последовательности как раньше, а затем отбирать среди них те, у которых k единиц — мы отбросим, считая его неэкономичным (число последовательностей с k единицами может быть много меньше числа всех последовательностей). Будем искать такой алгоритм, чтобы получение очередной последовательности требовало не более C . n действий. В каком случае s-ый член последовательности можно увеличить, не меняя предыдущие? Если x[s] меняется с 0 на 1, то для сохранения общего числа единиц нужно справа от х[s] заменить 1 на 0. Для этого надо, чтобы справа от x[s] единицы были. Если мы хотим перейти к непосредственно следующему, то x[s] должен быть первым справа нулём, за которым стоят единицы. Легко видеть, что х[s+1]=1 (иначе х[s] не первый). Таким образом надо искать наибольшее s, для которого х[s]=0, x[s+1]=1: За х[s+1] могут идти ещё несколько единиц, а после них несколько нулей. Заменив х[s] на 1, надо выбрать идущие за ним члены так, чтобы последовательность была бы минимальна с точки зрения нашего порядка, —е чтобы сначала шли нули, а потом единицы. Вот что получается:
s := n - 1; while not ((x[s]=0) and (x[s+1]=1)) do begin | s := s - 1; end; {s - член, подлежащий изменению с 0 на 1} num:=0; for k := s to n do begin | num := num + x[k]; end; {num - число единиц на участке x[s]...x[n], число нулей равно (длина - число единиц), т.е. (n-s+1) - num} x[s]:=1; for k := s+1 to n-num+1 do begin | x[k] := 0; end; {осталось поместить num-1 единиц в конце} for k := n-num+2 to n do begin | x[k]:=1; end; Источники и прецеденты использования |
© 2004-...
МЦНМО
(о копирайте)
|
Пишите нам
|