复杂决策树生成器

本文关键字:决策树 复杂 | 更新日期: 2023-09-27 18:03:20

我试图写一种二叉树,但它非常大,我不想在内存中保存每个元素。我更愿意在需要时使用生成器函数来构造每个节点。

树模拟了游戏中的决策。游戏以一帧n选项开始。玩家选择两个选项(不可能相同),并使用不同的操作将它们组合在一起。因此,一个框架有(n * (n-1)) * t可能采取的步骤,其中t是操作的数量。

一旦做出决定,它将产生一个新的n - 1选项框架,其中上次选择的两个选项已被删除,但这些选项的结果已包含在内。可能的不同选择的数量现在是((n - 1) * (n - 2)) * t。这个过程一直持续到当前帧中的选项数<= 1.

我想以一种特定的方式遍历决策树中所有可能的路径——在移动到下一个可能的路径之前,将每条路径遍历到最后一帧(其中n = 1),该路径从最大的一帧(size = n)开始,但在每一帧中采取下一系列选择。除了我在这里描述的结果之外,决策的结果对于这些目的并不重要。所有的路由都必须走到最后一帧(其中n = 1)——我不需要包括部分遍历的路由。

我有下面的代码,我想要生成要做出的决策的映射。:

public class PathStep
{
    public int FrameSize;
    public int Index1;
    public int Index2;
    public int Operation;
    public override string ToString()
    {
        return String.Format("F:{0} I1:{1} I2:{2} O{3}", this.FrameSize, this.Index1, this.Index2, this.Operation);
    }
}
public class Frame
{
    public int Size { get; private set; }
    public Frame(int size)
    {
        this.Size = size;
    }
    public IEnumerable<PathStep> AllPossibleSteps()
    {
        return this.step_helper(this.Size, 0);
    }
    private IEnumerable<PathStep> step_helper(int frame_size, int depth)
    {
        throw new NotImplementedException(); //TODO
    }

    private static IEnumerable<Frame> frames_in_game(int initial_frame_size)
    {
        for (var i = initial_frame_size; i > 0; i--)
            yield return new Frame(i);
    }
    private static IEnumerable<PathStep> steps_in_frame(int frame_size)
    {
        int op_count = Operation.Operations().Count();
        for (var first = 0; first < frame_size; first++)
        {
            for (var second = 0; second < frame_size - 1; second++)
            {
                for (var i = 0; i < op_count; i++)
                {
                    yield return new PathStep() { FrameSize = frame_size, Index1 = first, Index2 = second, Operation = i };
                }
            }
        }
    }

}

我如何填充我的step_helper方法来映射树中每个可能的决策变化,并按照连续博弈的顺序生成它们?我需要覆盖所有可能的路线,并且yield return在给定路线上的每一步都是顺序的,但是我走完整路线的顺序无关紧要,只要我覆盖它们就行了。

复杂决策树生成器

我重新思考了我的问题,并意识到以下几点:

如果 n * (n - 1) * t = options_per_frame

然后我可以将每条路径表示为选项的网格,(如果1被索引)从:

开始
   let t = 4
   n |n-1|t | n = ?
   1 |1  |1 | 6
   1 |1  |1 | 5
   1 |1  |1 | 4
   1 |1  |1 | 3
   1 |1  |1 | 2

紧随其后:

   n |n-1|t | n = ?
   1 |1  |1 | 6
   1 |1  |1 | 5
   1 |1  |1 | 4
   1 |1  |1 | 3
   1 |1  |2 | 2

结尾
   n |n-1|t | n = ?
   6 |5  |4 | 6
   5 |4  |4 | 5
   4 |3  |4 | 4
   3 |2  |4 | 3
   2 |1  |4 | 2

其中单元格中的每个值表示所选选项的索引/id,标题指定可以放入单元格中的最大值。所以,你可以把它想象成一个时钟——不同大小的"齿轮"用来相互旋转,所以变化是级联递减的。在时间上,1000毫秒"旋转"一秒,60秒"旋转"一小时,24小时"旋转"一天等等。所以我创建了一个PathGrid类,它返回网格的下一次迭代,这允许我一直沿着每条路径,而不必建模树或使用递归。我已经上传了我的解决方案