Я работал над этой проблемой в 2010 году, но тогда не смог найти решение.Несколько дней назад я еще раз взглянул на некоторые из моих записей того времени и подозревал, что был очень близок к решению.Через несколько минут у меня был ключ.
Чтобы подвести итоги: требуется строгое минимальное изменение порядка k-подмножеств строки s, чтобы LIFO (последний пришел первым вышел) был максимизирован.Я называю это «максимальным обменом» в более ранних публикациях.
Я называю алгоритм maxlifo (максимизированный LIFO) после требования ключа.Он принимает два параметра: строку s, которая не должна содержать повторяющихся символов, и положительное целое число k, не превышающее размер s.Алгоритм является рекурсивным, то есть maxlifo (s, k) использует вывод maxlifo (s, k-1) вплоть до k = 1.Вывод возвращается в виде списка.
Ниже я приведу неформальное объяснение, с примерами, используя строку «abcdefg» и различные значения k.Далее следует пример реализации в качестве процедуры Unicon.(Я не владею ни одним из наиболее часто используемых языков.)
Случай k = 1 тривиален - он возвращает элементы s в порядке от первого до последнего.
Дляk> 1, примените следующие правила к выводу maxlifo (s, k-1):
(1) Для каждого элемента вывода maxlifo (s, k-1) список в строкеk-подмножества, построенные из этого элемента, с каждым пропущенным символом s по очереди.Порядок символов в подмножествах такой же, как в s.
(2) Работая от второй строки вниз, замените пустые «заполнители» для всех вхождений подмножеств, которые появляются в более ранней строке.Теперь каждое k-подмножество s появляется только один раз.
(3) В каждой непустой строке отметьте начальную букву!каждое подмножество так, чтобы в следующей строке был заполнитель в той же позиции.Эта маркировка означает «первый».Ровно одно подмножество будет помечено в каждой непустой строке.
(4) Удалите все пустые строки (содержат только заполнители).
(5) В каждой оставшейся строке, кромепоследнее, отметьте финалом!подмножество в позиции, соответствующей подмножеству, помеченному как «первый» в следующей нижней строке.Эта маркировка означает «последний».
Теперь мы можем перечислить окончательный порядок подмножеств maxlifo.Каждая строка сверху вниз упорядочена, и ее элементы добавлены в указанном порядке в список вывода.
(6) В каждой строке сверху вниз:
(6.1) Удалите все пустые заполнители.
(6.2) Добавьте в список вывода подмножество, помеченное как «первое» (начальное!), И удалите его из строки.
(6.3) Если в строке еще есть подмножествалибо самое левое, либо самое правое подмножество будет помечено как «последний» (последний!).Если крайнее правое подмножество помечено как «последнее», добавьте подмножества в список вывода по порядку слева направо, в противном случае по порядку справа налево.
(7) После обработки всех строк верните список вывода.
Пример использования maxlifo ("abcdefg", 2):
Col1 содержит вывод maxlifo ("abcdefg", 1).Строки Col2 содержат клики, образованные с оставшимися символами s:
Col1 Col2
---- ----------------------------
a ab ac ad ae af ag
b ab bc bd be bf bg
c ac bc cd ce cf cg
d ad bd cd de df dg
e ae be ce de ef eg
f af bf cf df ef fg
g ag bg cg dg eg fg
Выделить подмножества, которые появляются в более ранней строке:
a ab ac ad ae af ag
b bc bd be bf bg
c cd ce cf cg
d de df dg
e ef eg
f fg
g
Отметить «первое» подмножество вкаждая строка (строка с пробелом под ней):
a !ab ac ad ae af ag
b !bc bd be bf bg
c !cd ce cf cg
d !de df dg
e !ef eg
f !fg
g
Удалить все полностью пустые строки (в данном случае только одну):
a !ab ac ad ae af ag
b !bc bd be bf bg
c !cd ce cf cg
d !de df dg
e !ef eg
f !fg
Отметить «последнее» подмножество вкаждая строка (та, у которой под первым «подмножеством»).
a !ab ac! ad ae af ag
b !bc bd! be bf bg
c !cd ce! cf cg
d !de df! dg
e !ef eg!
f !fg
Выведите каждую строку в порядке, описанном выше: «first», без опознавательных знаков, «last»:
Ordered rows:
a !ab ac! ad ae af ag ab ag af ae ad ac
b !bc bd! be bf bg bc bg bf be bd
c !cd ce! cf cg cd cg cf ce
d !de df! dg de dg df
e !ef eg! ef eg
f !fg fg
Вывод: [ab ag af ae ad ac bc bg bf быть bd cd cg cf ce df dg de ef, например, fg]
Примеры для 3 <= k <= 6 приведены менее подробно.Пустые строки, удаленные на шаге 4, остаются на месте. </p>
maxlifo ("abcdefg", 3):
Ordered rows:
ab !abc abd abe abf abg! abc abd abe abf abg
ag acg adg aeg! !afg afg acg adg aeg
af acf adf! !aef aef acf adf
ae ace! !ade ade ace
ad !acd! acd
ac
bc !bcd bce bcf bcg! bcd bce bcf bcg
bg bdg beg! !bfg bfg bdg beg
bf bdf! !bef bef bdf
be !bde! bde
bd
cd !cde cdf cdg! cde cdf cdg
cg ceg! !cfg cfg ceg
cf !cef! cef
ce
de !def deg! def deg
dg !dfg! dfg
df
ef !efg efg
eg
fg
Вывод: [abc abd abe abf abg afg acg adg aeg aef acfadf ade ace acd
bcd bce bcf bcg bfg bdg beg bef bdf bde cde cdf cdg cfg ceg cef def deg dfg efg]
maxlifo ("abcdefg", 4):
Ordered rows:
abc !abcd abce! abcf abcg abcd abcg abcf abce
abd !abde abdf! abdg abde abdg abdf
abe !abef abeg! abef abeg
abf !abfg! abfg
abg
afg acfg! adfg !aefg aefg adfg acfg
acg !acdg aceg! acdg aceg
adg !adeg! adeg
aeg
aef acef! !adef adef acef
acf !acdf! acdf
adf
ade !acde! acde
ace
acd
bcd !bcde bcdf! bcdg bcde bcdg bcdf
bce !bcef bceg! bcef bceg
bcf !bcfg! bcfg
bcg
bfg bdfg! !befg befg bdfg
bdg !bdeg! bdeg
beg
bef !bdef! bdef
bdf
bde
cde !cdef cdeg! cdef cdeg
cdf !cdfg! cdfg
cdg
cfg !cefg! cefg
ceg
cef
def !defg defg
deg
dfg
efg
Вывод: [abcd abcg abcf abce abde abdg abdf abef abeg abfg aefg adfg acfg acdg aceg adeg adef acef acdf acde
bcde bcdg bcdf bcef bceg bcfg befg bdfg bdeg bdef
cdef cdeg cdfg cefg
DEFG]
maxlifo ("abcdefg", 5):
Ordered rows:
abcd !abcde abcdf abcdg! abcde abcdf abcdg
abcg abceg! !abcfg abcfg abceg
abcf !abcef! abcef
abce
abde !abdef abdeg! abdef abdeg
abdg !abdfg! abdfg
abdf
abef !abefg! abefg
abeg
abfg
aefg acefg! !adefg adefg acefg
adfg !acdfg! acdfg
acfg
acdg !acdeg! acdeg
aceg
adeg
adef !acdef! acdef
acef
acdf
acde
bcde !bcdef bcdeg! bcdef bcdeg
bcdg !bcdfg! bcdfg
bcdf
bcef !bcefg! bcefg
bceg
bcfg
befg !bdefg! bdefg
bdfg
bdeg
bdef
cdef !cdefg cdefg
cdeg
cdfg
cefg
defg
Вывод: [abcde abcdf abcdg abcfg abceg abcef abdef abdef abdeg abdfg abefg adefg acefg acdfg acdeg acdef
bcdef bcdeg bcdfg bcefg bdefg
cdefg]
maxlifo ("abcdefg", 6):
Ordered rows:
abcde !abcdef abcdeg! abcdef abcdeg
abcdf !abcdfg! abcdfg
abcdg
abcfg !abcefg! abcefg
abceg
abcef
abdef !abdefg! abdefg
abdeg
abdfg
abefg
adefg
acefg !acdefg! acdefg
acdfg
acdeg
acdef
bcdef !bcdefg bcdefg
bcdeg
bcdfg
bcefg
bdefg
cdefg
Вывод: [abcdef abcdeg abcdfg abcefg abdefg acdefg bcdefg]
Реализация Unicon:
procedure maxlifo(s:string, k:integer)
# A solution to my combinatorics problem from 2010.
# Return a list of the k subsets of the characters of a string s
# in a minimal change order such that last-in first-out is maximised.
# String s must not contain duplicate characters and in the present
# implementation must not contain "!", which is used as a marker.
local ch, cand, Hit, inps, i, j, K, L, Outp, R, S
# Errors
if *cset(s) ~= *s then
stop("Duplicate characters in set in maxlifo(", s, ", ", k, ")")
if find("!", s) then
stop("Illegal character in set in maxlifo(", s, ", ", k, ")")
if k > *s then
stop("Subset size larger than set size in maxlifo(", s, ", ", k, ")")
# Special cases
if k = 0 then return []
if k = *s then return [s]
Outp := []
if k = 1 then {
every put(Outp, !s)
return Outp
}
# Default case
S := set()
K := []
# Build cliques from output of maxlifo(s, k-1) with the remaining
# characters in s, substituting empty strings as placeholders for
# subsets already listed.
every inps := !maxlifo(s, k-1) do {
R := []
every ch := !s do
if not find(ch, inps) then {
cand := reorder(inps ++ ch, s)
if member(S, cand) then cand := "" else insert(S, cand)
put(R, cand)
}
put(K, R)
}
# Mark ‘first’ subset in each row with initial "!"
every i := 1 to *K - 1 do {
every j := 1 to *K[i] do
if K[i, j] ~== "" & K[i+1, j] == "" then {
K[i, j] := "!" || K[i, j]
break
}
}
# Remove rows containing only placeholders
every i := *K to 1 by -1 do {
every if !K[i] ~== "" then break next
delete(K, i)
}
# Mark ‘last’ subset in each row with final "!"
every i := 1 to *K - 1 do
every j := 1 to *K[i] do
if K[i+1, j][1] == "!" then {
K[i, j] ||:= "!"
break
}
# Build output list
every R := !K do {
# Delete placeholders from row (no longer needed and in the way)
every j := *R to 1 by -1 do if R[j] == "" then delete(R, j)
# Handle ‘first’ subset and remove from row
# N.B. ‘First’ subset will be leftmost or rightmost in row
if R[1][1] == "!" then
put(Outp, trim(get(R), '!', 0))
else put(Outp, trim(pull(R), '!', 0))
# Handle any remaining subsets, ‘last’ subset last, stripping '!' markers
# N.B. ‘Last’ subset will be leftmost or rightmost in row after removal
# of ‘first’ subset.
if R[-1][-1] == "!" then while put(Outp, trim(get(R), '!', 0)) else
while put(Outp, trim(pull(R), '!', 0))
}
return Outp
end
procedure reorder(cs:cset, s:string)
# Reorder cset cs according to string s
local r
# If no s, return set in alphabetical order
if /s then return string(cs)
r := ""
s ? while tab(upto(cs)) do r ||:= move(1)
return r
end