如何排版MinMax算法树?

如何排版MinMax算法树?

我想要在 LaTeX 中排版 MinMax 决策树,就像下图这样:

我想要实现的目标的草图

我进行了一些尝试并实现了部分目标:

\documentclass{article}

\usepackage{tikz,tikz-qtree} 
\usetikzlibrary{backgrounds}

\newcommand{\ply}[3][black]{\footnotesize{#2 ({\color{#1}#3})}}
\newcommand{\player}[1]{\footnotesize \emph #1}

\begin{document}

\begin{tikzpicture}[framed]
\Tree [.{} \edge[opacity=0]; [.\player{MAX:} \edge[opacity=0]; 
                              [.\player{MIN:} \edge[opacity=0]; 
                               [.\player{MAX:} \edge[opacity=0]; 
                                [.\player{MIN:} ]]]]
           \edge[opacity=0]; 
            [.\ply[red]{4}{+1}
              \edge node[auto=right]{-1}; 
              [. \ply[red]{3}{-1} 
                 \edge node[auto=right]{-1}; 
                 [. \ply[red]{2}{+1}
                    \edge node[auto=right]{-1}; [.\ply{1}{+1} ] ]
                 \edge node[auto=left]{-2}; \ply{1}{-1} ]
              \edge node[auto=right]{-2}; \ply[red]{2}{-1}
              \edge node[auto=left]{-3}; \ply{1}{+1}
              ]]
\end{tikzpicture}     

\end{document}

到目前为止我所拥有的 Latex 输出

我还需要实现一些功能:

  • 减少图片顶部的边距(删除不可见的根节点)
  • 使边缘标签尺寸更小,最好是 \scriptsize
  • 从图纸中添加红色向上箭头
  • 如果可能的话,让 MIN / MAX 标签右对齐

我对 tikz 的了解不足以做这些事情,所以如果有人能帮助我,我将非常感激!

答案1

你感觉自己有多勇敢?

以下解决方案使用基于的实验包forest。似乎没人愿意测试prooftrees,所以我想我也尝试justtrees一下。

首先,结果:

justtrees 树

接下来是代码:

\documentclass[tikz,border=5pt,multi]{standalone}
\usepackage{justtrees}
\usepackage{cfr-lm}% for italic small-caps
\newcommand{\ply}[3][black]{\footnotesize{#2 ({\color{#1}#3})}}
\newcommand{\player}[1]{\footnotesize \emph #1}

\begin{document}

  \begin{forest}
    just tree,
    just format/.style={font=\sishape},% italic small-caps
    for tree={
      font=\tlstyle,% for tabular, lining figures with cfr-lm
      alias/.wrap 2 pgfmath args={#1-#2}{int(subtract(level(),1))}{n()}% labels the nodes systematically so we can refer to them later
    },
    my edge label/.style n args=2{% save typing when creating the edge labels
      edge label={node [midway, font=\scriptsize\tlstyle, #1] {#2}}
    },
    [, phantom
      [{\ply[red]{4}{+1}}, left just={Max:}
        [{\ply[red]{3}{-1}}, left just={Min:}, my edge label={left}{-1}
          [{\ply[red]{2}{+1}}, left just={Max:}, my edge label={left}{-1}
            [{\ply{1}{+1}}, left just={Min:}, my edge label={left}{-1}
            ]
          ]
          [{\ply{1}{-1}}, my edge label={left}{-2}]
        ]
        [{\ply[red]{2}{-1}}, calign with current, my edge label={left, pos=.75}{-2}]
        [{\ply{1}{+1}}, my edge label={right}{-3}]
      ]
    ]
    \tikzset{->}
    \draw [red] (1-3.north) [bend right] to (0-1.east);
    \draw [red] ([xshift=2.5pt]3-1.north) [bend right] to ([xshift=2.5pt]2-1.south);
    \draw [red] (2-2.north) [bend right] to (1-1.east);
  \end{forest}

\end{document}

最后,打包(保存justtrees.sty在与文档相同的目录中):

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{justtrees}[2015/05/30 v0.01 justtrees]
\RequirePackage{forest}
\newcounter{justtree@countlevels}% count the levels in the just tree
\setcounter{justtree@countlevels}{0}
\newcount\justtree@lcount% count the left justifiers (on the left)
\newcount\justtree@rcount% count the right justifiers (on the right)
\forestset{
  just format/.style={font=\normalfont\normalsize},
  declare boolean={left justifiers}{0},% left justifications
  declare boolean={right justifiers}{0},% right justifications
  right justifier/.style={% creates the right justifiers on the right but does not yet specify any content
    anchor=base west,
    no edge,
    before typesetting nodes={% page 51
      TeX={\advance\justtree@rcount1},
      name/.expanded={right just \the\justtree@rcount},% name them so they can be moved
      if={\the\justtree@rcount>2}{% correct the location as for the left justifiers
        for previous={
          append/.expanded={right just \the\justtree@rcount}
        },
      }{},
    },
  },
  left justifier/.style={% creates the left justifiers on the left but does not yet specify any content
    anchor=base east,
    no edge,
    before typesetting nodes={% page 51
      TeX={\advance\justtree@lcount1},
      name/.expanded={left just \the\justtree@lcount},% name them so they can be moved
      if={\the\justtree@lcount>2}{% correct the location as for the left justifiers
        for previous={
          append/.expanded={left just \the\justtree@lcount}
        },
      }{},
    },
  },
  left justifications/.style={
    for tree={left justifiers},
  },
  no left justifications/.style={
    for tree={not left justifiers},
  },
  right justifications/.style={
    for tree={right justifiers},
  },
  no right justifications/.style={
    for tree={not right justifiers},
  },
  just tree/.style={
    for tree={
      parent anchor=south,
      delay={
        where content={}{
          shape=coordinate,
        }{}
      },
    },
    where level=0{
      for children={
        no edge,
      },
      delay={
        if={(\forestove{left justifiers}==1) || (\forestove{right justifiers}==1)}{% count the levels if necessary
          for descendants={
            if={level()>\value{justtree@countlevels}}{
              TeX={
                \stepcounter{justtree@countlevels}
              },
            }{},
          },
        }{},
        if={(\forestove{left justifiers}==1)}{% create the left justifiers if appropriate
          prepend={
            [,
              fit=rectangle,
              just format,
              left justifier,
              repeat={\value{justtree@countlevels}-1}{% most are created in the wrong place but they are moved later
                delay n={\the\justtree@lcount}{
                    append={[, left justifier, just format]}
                },
              }
            ]
          },
        }{},
        if={(\forestove{right justifiers}==1}{% create the nodes which will hold the right justifiers, if required
          append={
            [,
              fit=rectangle,
              right justifier,
              just format,
              repeat={\value{justtree@countlevels}-1}{% most are created in the wrong place but right justifier moves them later
                delay n={\the\justtree@rcount}{
                  append={[, right justifier, just format]}
                },
              }
            ]
          }
        }{},
      },
    }{},
    before packing={
      for tree={
        tier/.wrap pgfmath arg={tier ##1}{level()},
      },
    },
  },
  right just/.style={
    if={\forestove{right justifiers}==0}{
      for root={
        right justifiers,
      },
    }{},
      before packing={% puts the content of the right justifiers into the empty right justifier nodes on the right; because this is done late, the nodes need to be typeset again
        for={name/.wrap pgfmath arg={right just ##1}{level()}}{
          content={#1},
          typeset node
        },
      }
  },
  left just/.style={
    if={\forestove{left justifiers}==0}{
      for root={
        left justifiers,
      },
    }{},
    before packing={% puts the content of the left justifiers into the empty left justifier nodes on the left; because this is done late, the nodes need to be typeset again
      for={name/.wrap pgfmath arg={left just ##1}{level()}}{
        content={#1},
        typeset node
      },
    }
  },
}
\endinput
%% end justtrees.sty

我本来想匿名发布此文,但这对于实验性代码来说似乎不公平,所以我又违反了我的规则。唉。

相关内容