在树中正确实现Min-Max

时间:2017-04-10 09:39:00

标签: algorithm tree minmax

我在树上实现了min-max算法。我创建的算法按预期工作,返回树中与最小值和最大值对应的路径。但我的问题是它感觉不对。我的问题是,min-max算法的正确实现是什么?
我在由节点组成的树结构中找不到该算法的纯实现。在我设法找到的例子中,人们实现了算法来解决与游戏相关的问题(tic-tac-toe)。说实话,我感到愚蠢,我无法建立联系 我使用了2个功能,
1-> evaluateations_function,它遍历树并为没有的节点增加值(例如,所有节点都不是叶子)。
2-> print_optimal,它遍历树并返回路径。

public void evaluation_function(Node root, int maxHeight, int rootHeight) {
        if (root.childrenList.Count != 0) {
            foreach (Node node in root.childrenList) {
                evaluation_function(node, maxHeight, rootHeight);
            }
        }
        if (root.height != rootHeight) {
            if ((root.height % 2) == 0) {
                if (root.value < root.parent.value || root.parent.value == 123456) {
                    root.parent.value = root.value;
                }
            } else if ((root.height % 2) != 0) {
                if (root.value > root.parent.value || root.parent.value == 123456) {
                    root.parent.value = root.value;
                }
            }
        }
    }

这是print_optimal

public void print_optimal(Node root) {
        int maxValue = 0;
        int minValue = 9999;
        if (root.childrenList.Count != 0) {
            if (root.height % 2 == 0) {
                foreach (Node child in root.childrenList) {
                    if (child.value > maxValue) { maxValue = child.value; }
                }
                foreach (Node child in root.childrenList) {
                    if (child.value == maxValue) {
                        Console.WriteLine("Selected node " + child.name
                            + " with value = " + child.value + " as MAX player");
                        print_optimal(child);
                    }
                }
            } else {
                foreach (Node child in root.childrenList) {
                    if (child.value < minValue) { minValue = child.value; }
                }
                foreach (Node child in root.childrenList) {
                    if (child.value == minValue) {
                        Console.WriteLine("Selected node " + child.name
                            + " with value = " + child.value + " as MIN player");
                        print_optimal(child);
                    }
                }
            }
        }
    }

我不想用代码来解决问题,因为我的问题是理论上的。但是,如果您想查看数据结构或想要测试算法,可以在此处找到它:https://github.com/AcidDreamer/AI_Exercises/tree/master/1.2.1/Exercise1_2_1/Exercise1_2_1


改进
evaluation_function已更改为

public void evaluation_function(Node root, int rootHeight) {
        if (root.childrenList.Count != 0) {
            foreach (Node node in root.childrenList) {
                evaluation_function(node, rootHeight);
            }
        }
        if (root.height != rootHeight || root.childrenList.Count != 0) {
            int maxValue = 0, minValue = 999;
            if ((root.height % 2) == 0) {
                foreach (Node child in root.childrenList) {
                    if (maxValue < child.value) {
                        maxValue = child.value;
                        root.value = maxValue;
                        root.bestChild = child;
                    }
                }
            } else if ((root.height % 2) != 0) {
                foreach (Node child in root.childrenList) {
                    if (minValue > child.value) {
                        minValue = child.value;
                        root.value = minValue;
                        root.bestChild = child;
                    }
                }
            }
        }
    }

为当前节点赋值。
print_optimal使用bestChild字段有了很大的改进,并且更改为

public void print_optimal(Node root) {
        if (root.bestChild != null) {
            Console.Write(root.name + "->");
            print_optimal(root.bestChild);
        } else {
            Console.WriteLine(root.name);
        }
    }

2 个答案:

答案 0 :(得分:1)

我发现接收节点作为输入的evaluation_function实际上更新了父节点的值,这有点不自然。

我觉得更好的方法是让该函数更新当前节点。

如果当前节点是叶子,它将不执行任何操作。

否则,它应遍历所有子节点(正如它在第一个循环中所做的那样),并且在每次递归调用子节点之后,还应该检查当前节点值是否应该更新( ie < / em>当前孩子刚刚遇到了更好的价值。

此外,可以为每个节点添加一个额外的字段,例如 bestChildbestMove,以避免在调用{{{{{{}时重新遍历子节点。 1}}。

答案 1 :(得分:1)

总的来说,你的代码很好(你知道,因为它有效),但我对改进有一些评论:

evaluation_function :您根本不使用maxHeight。使用它或删除参数。该函数改变当前节点的父节点是一种奇怪的(一种不好的做法)。它应该查看子项的值(如果不是叶子),并根据它更新当前节点的值。此外,您可以添加一个字段来跟踪最佳子项(甚至是选定的叶子路径),以避免print _最佳匹配过程。

print_optimal():如果2个孩子具有相同的值,则您当前遇到问题:您将打印这两个孩子并浏览这两个树。检查if (child.value < minValue) { minValue = child.value; }是没用的,因为您认为自己已经使用过evaluation_function(),并且仅仅取代&#34; evaluation_function如果您忘记这样做了。