我想使用 LaTeX 打印集合的排列{s,u,v,a,t}
。输出如下所示。
suvat
suvta
suavt
suatv
...
总共有 120 行必须即时生成。
如何用 LaTeX 做到这一点?
梅威瑟:
\documentclass{article}
\begin{document}
.
\end{document}
答案1
这是一个更好的版本,有很多注释!顺便说一句,生成所有排列的方法是基于克努斯洗牌。
最新版本的代码避免了嵌套循环,并且分隔符\par
偶尔会变成一个标记,以避免构建太大的框(请参阅评论中的讨论)。我用它运行了它abcdefghij
并且成功了,尽管生成的文档长达 13746 页。
\documentclass{article}
%\url{http://tex.stackexchange.com/q/112975/86}
\usepackage{expl3}
\usepackage{xparse}
\ExplSyntaxOn
\tl_new:N \l__perm_all_tl
\int_new:N \l__perm_int
\int_new:N \l__perm_len_int
% Print the permutations of #2 with prefix #1
\cs_new_nopar:Npn \generate_perms:nn #1#2
{
% We need to recursively call this function to build up the
% final list. This presents us with a dilemma. Inside the
% function we need to do some token list manipulations. These
% must not propagate upwards to the calling function. One way
% to avoid this is to have the function be within a group, but
% that has two disadvantages: the simplest way leads to a lot of
% nested groups, and if we want to store the result rather than
% simply typeset it then the assignments have to be global.
% So we choose an alternative way which is to ensure that any
% temporary variables are used as soon as possible after
% definition and never span a recursive call to the function.
% This makes the function mildly inefficient in that we can't
% store and reuse some calculations.
%
% How many terms do we need to permute?
\int_set:Nn \l__perm_len_int {\tl_count:n {#2}}
\int_compare:nTF {\l__perm_len_int <= 1}
{
% Only one, so nothing to do.
% Add it to the stream with the separator in front.
\l__perm_sep: #1#2
}
{
% More than one, so need to do the permutations.
% The method is based on the Knuth shuffle.
% We need to generate all of the permutations. We can do this
% recursively by the following algorithm. We cyclically permute
% the token list. For each cyclic permutation we freeze the first
% term and then apply the permutation generation function to the
% rest of the list.
%
% Thus if we start with abc we generate the cyclic permutations.
% These are abc, bca, cab.
% Then for each of these, we freeze the first term and apply the
% function to the rest: so with abc we freeze the a and apply the
% generation function to bc. This will (by recursion) generate
% bc and cb, whence appending the a again yields abc and acb.
%
% To avoid nesting loops, each iteration creates a token list of
% what it would do and that list is then inserted into the stream.
\tl_clear:N \l__perm_all_tl
\tl_set:Nn \l_tmpb_tl {#2}
% We "freeze" the first term, adding it to the current prefix.
\tl_set:Nn \l_tmpa_tl {#1}
\tl_put_right:Nx \l_tmpa_tl {\tl_head:N \l_tmpb_tl}
% Now we add the first call to the recursive function to the
% token list for this iteration.
% This consists of a call to the function with arguments
% the new prefix and the new tail. We pass in the values so
% that we can now use our temporary variables again with aplomb.
\tl_put_right:Nn \l__perm_all_tl {\generate_perms:nn}
\tl_put_right:Nx \l__perm_all_tl {{\exp_not:V \l_tmpa_tl}}
\tl_put_right:Nx \l__perm_all_tl {{\tl_tail:N \l_tmpb_tl}}
% Now we repeat the above but applying a cyclic permutation
% to the main token list first
\prg_replicate:nn {\l__perm_len_int - 1}
{
% This applies a cyclic permutation to the token list.
\tl_set:Nx \l_tmpb_tl {\tl_tail:N \l_tmpb_tl {\tl_head:N \l_tmpb_tl}}
% Then we add the function call to the token list.
\tl_set:Nn \l_tmpa_tl {#1}
\tl_put_right:Nx \l_tmpa_tl {\tl_head:N \l_tmpb_tl}
\tl_put_right:Nn \l__perm_all_tl {\generate_perms:nn}
\tl_put_right:Nx \l__perm_all_tl {{\exp_not:V \l_tmpa_tl}}
\tl_put_right:Nx \l__perm_all_tl {{\tl_tail:N \l_tmpb_tl}}
}
% The token list now contains all the needed recursive calls
% which we can now call.
\l__perm_all_tl
}
}
\cs_generate_variant:Nn \generate_perms:nn {VV}
% The optional argument is the separator, the mandatory one is the
% token list to permute.
\DeclareDocumentCommand \permute { O{,~} m }
{
% Set the separator
\set_separator:n {#1}
% Generate the permutation list
\generate_perms:nn {} {#2}
}
% This sets the separator. The first separator typesets nothing but
% sets all the subsequent separators. Normally the separator inserts
% the optional argument from the user but every 120 terms it inserts
% a \par token instead to avoid overload.
\cs_new_nopar:Npn \set_separator:n #1
{
\int_zero:N \l__perm_int
\cs_set:Npn \l__perm_sep:
{
\cs_set:Npn \l__perm_sep:
{
\int_incr:N \l__perm_int
\int_compare:nTF {\l__perm_int == 120}
{
\par
\int_zero:N \l__perm_int
}
{
#1
}
}
}
}
\ExplSyntaxOff
\parskip=1em plus 1ex minus .5ex
\begin{document}
\noindent\raggedright\permute{abcdefghi}
\end{document}
答案2
使用正确的工具来完成工作:
\documentclass{article}
\usepackage{python}
\begin{document}
\begin{python}
import itertools
for p in itertools.permutations("suvat"): print ''.join(p)
\end{python}
\end{document}
用 运行它pdflatex -shell-escape
。
答案3
该\permute
宏是纯 TeX,因此非常便于移植。为什么你不想让它神秘?它神秘地完成了工作!
% New simplified code -- less cryptic than before :-)
\documentclass{article}
\def\recurse#1#2#3#4\endmarker{%
\dopermute{#1#3}#2#4\endmarker
\ifx\relax#4\relax\else % add a \par before \else if there are more than 8 items
\recurse{#1}{#2#3}#4\endmarker
\fi}
\def\dopermute#1#2#3\endmarker{%
\ifx\relax#3\relax
#1#2,
\else
\dopermute{#1#2}#3\endmarker
\recurse{#1}{#2}#3\endmarker
\fi}
\newcommand*\permute[1]{\dopermute{}#1\endmarker}
\begin{document}
\noindent\raggedright
\permute{12345}
\end{document}
注意\permute
很挑剔,想要被喂食单个标记,所以\permute{12{34}}
不会起作用,但\newcommand*\tf{34}\permute{12\tf}
会起作用。(你真的想改变这样的事情吗?)
答案4
简单LaTeX
代码,仅限 5 个字符:
\documentclass[10pt,a4paper]{article}
\usepackage[english]{babel}
\usepackage{pgffor}
\def\defPerm|#1#2#3#4#5|{\lccode`\1`#1\lccode`\2`#2\lccode`\3`#3\lccode`\4`#4\lccode`\5`#5}
\def\typePerm#1#2#3#4#5{\char\the\lccode`#1\char\the\lccode`#2\char\the\lccode`#3\char\the\lccode`#4\char\the\lccode`#5}%
\def\permuteV#1{{\defPerm|#1|\def\tmp{\foreach\next in {%
12345,12354,12435,12453,12534,12543,13245,13254,13425,13452,13524,13542,
14235,14253,14325,14352,14523,14532,15234,15243,15324,15342,15423,15432,
21345,21354,21435,21453,21534,21543,23145,23154,23415,23451,23514,23541,
24135,24153,24315,24351,24513,24531,25134,25143,25314,25341,25413,25431,
31245,31254,31425,31452,31524,31542,32145,32154,32415,32451,32514,32541,
34125,34152,34215,34251,34512,34521,35124,35142,35214,35241,35412,35421,
41235,41253,41325,41352,41523,41532,42135,42153,42315,42351,42513,42531,
43125,43152,43215,43251,43512,43521,45123,45132,45213,45231,45312,45321,
51234,51243,51324,51342,51423,51432,52134,52143,52314,52341,52413,52431,
53124,53142,53214,53241,53412,53421,54123,54132,54213,54231,54312,54321}
{\expandafter\typePerm\next{} }}\tmp}}%
%
\begin{document}
\noindent\permuteV{suvat}
\noindent\permuteV{LaTeX}
\noindent\texttt{\permuteV{@1234}}
\end{document}