Это проблема подсчета, а не проблема построения, поэтому мы можем подойти к ней с помощью рекурсии. Поскольку задача состоит из двух естественных частей: взгляда слева и взгляда справа, разбейте ее и сначала решите только одну часть.
Позвольте b(N, L, R)
быть числом решений, и пусть f(N, L)
будет количеством компоновок блоков N
, чтобы L
были видны слева. Сначала подумайте о f
, потому что это проще.
ПОДХОД 1
Давайте получим начальные условия и затем перейдем к рекурсии. Если все должно быть видно, то их нужно упорядочивать все чаще, поэтому
f(N, N) = 1
Если предполагается, что блоков больше, чем доступных, то мы ничего не можем сделать, поэтому
f(N, M) = 0 if N < M
Если должен быть виден только один блок, сначала поместите самый большой, а затем остальные могут следовать в любом порядке, поэтому
f(N,1) = (N-1)!
Наконец, для рекурсии подумайте о положении самого высокого блока, скажем, N
находится в k
-ом месте слева. Затем выберите блоки, которые должны стоять перед ним, 1027 * способами, расположите эти блоки так, чтобы ровно L-1
были видны слева, и расположите блоки N-k
позади N
в любом понравившемся вам месте, получив:
f(N, L) = sum_{1<=k<=N} (N-1 choose k-1) * f(k-1, L-1) * (N-k)!
Фактически, поскольку f(x-1,L-1) = 0
для x<L
, мы можем также начать k
с L
вместо 1
:
f(N, L) = sum_{L<=k<=N} (N-1 choose k-1) * f(k-1, L-1) * (N-k)!
Правильно, теперь, когда понятный бит понят, давайте используем f
для определения более сложного бита b
. Опять же, используйте рекурсию, основанную на положении самого высокого блока, снова скажите, N
находится в положении k
слева. Как и прежде, выберите блоки перед ним 1046 * способами, но теперь подумайте о каждой стороне этого блока отдельно. Для k-1
блоков слева от N
убедитесь, что именно L-1
из них видны. Для N-k
блоков справа от N
убедитесь, что R-1
видимы, а затем измените порядок, который вы получите от f
. Поэтому ответ:
b(N,L,R) = sum_{1<=k<=N} (N-1 choose k-1) * f(k-1, L-1) * f(N-k, R-1)
, где f
полностью разработано выше. Опять же, многие термины будут равны нулю, поэтому мы хотим взять k
, чтобы k-1 >= L-1
и N-k >= R-1
, чтобы получить
b(N,L,R) = sum_{L <= k <= N-R+1} (N-1 choose k-1) * f(k-1, L-1) * f(N-k, R-1)
ПОДХОД 2
Я снова подумал об этой проблеме и нашел несколько более хороший подход, позволяющий избежать суммирования.
Если вы решаете проблему противоположным образом, то есть добавляете наименьший блок вместо самого большого блока, то повторение для f
становится намного проще. В этом случае при тех же начальных условиях повторяемость составляет
f(N,L) = f(N-1,L-1) + (N-1) * f(N-1,L)
, где первый член, f(N-1,L-1)
, происходит от размещения наименьшего блока в крайнем левом положении, добавляя тем самым еще один видимый блок (следовательно, L
уменьшается до L-1
), а второй член, (N-1) * f(N-1,L)
, учитывает помещение наименьшего блока в любую из N-1
не передних позиций, в этом случае он не виден (следовательно, L
остается фиксированным).
Преимущество этой рекурсии состоит в том, что она всегда уменьшается на N
, хотя и затрудняет просмотр некоторых формул, например f(N,N-1) = (N choose 2)
. Эту формулу довольно легко показать из предыдущей формулы, хотя я не уверен, как правильно вывести ее из этого более простого повторения.
Теперь, чтобы вернуться к исходной проблеме и решить ее для b
, мы также можем использовать другой подход. Вместо суммирования ранее представьте видимые блоки как поступающие в пакетах, так что если блок виден слева, то его пакет состоит из всех блоков справа от него и перед следующим блоком, видимым слева, и аналогично, если блок виден справа, то его пакет содержит все оставшиеся от него блоки до следующего видимого справа блока. Сделайте это для всех, кроме самого высокого блока. Это делает для L+R
пакетов. Учитывая пакеты, вы можете переместить один из левой стороны в правую сторону, просто изменив порядок блоков. Следовательно, общий случай b(N,L,R)
фактически сводится к решению случая b(N,L,1) = f(N,L)
, а затем к выбору того, какой из пакетов поместить слева, а какой - справа. Поэтому у нас есть
b(N,L,R) = (L+R choose L) * f(N,L+R)
Опять же, эта переформулировка имеет некоторые преимущества по сравнению с предыдущей версией. Соединяя эти две последние формулы вместе, гораздо проще увидеть сложность общей проблемы. Однако я все еще предпочитаю первый подход к построению решений, хотя, возможно, другие не согласятся. В целом, это говорит о том, что есть более одного хорошего способа решения проблемы.
Что с числами Стирлинга?
Как указывает Джейсон, числа f(N,L)
- это точно (без знака) числа Стирлинга первого рода . Это можно увидеть сразу по рекурсивным формулам для каждого. Тем не менее, всегда приятно видеть его напрямую, так что вот так.
(Без знака) числа Стирлинга Первого Вида, обозначенные как S(N,L)
, подсчитывают количество перестановок N
в L
циклов. Учитывая перестановку, записанную в нотации цикла, мы записываем перестановку в канонической форме, начиная цикл с наибольшим числом в этом цикле, а затем все больше упорядочивая циклы по первому номеру цикла. Например, перестановка
(2 6) (5 1 4) (3 7)
будет записан в канонической форме как
(5 1 4) (6 2) (7 3)
Теперь отбросьте скобки и обратите внимание, что если это высота блоков, то количество видимых блоков слева - это точно количество циклов! Это связано с тем, что первое число каждого цикла блокирует все остальные числа в цикле, а первое число каждого последующего цикла видно за предыдущим циклом. Следовательно, эта проблема на самом деле является хитрым способом попросить вас найти формулу для чисел Стирлинга.