我在树上实现了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);
}
}
答案 0 :(得分:1)
我发现接收节点作为输入的evaluation_function
实际上更新了父节点的值,这有点不自然。
我觉得更好的方法是让该函数更新当前节点。
如果当前节点是叶子,它将不执行任何操作。
否则,它应遍历所有子节点(正如它在第一个循环中所做的那样),并且在每次递归调用子节点之后,还应该检查当前节点值是否应该更新( ie < / em>当前孩子刚刚遇到了更好的价值。
此外,可以为每个节点添加一个额外的字段,例如 bestChild
或bestMove
,以避免在调用{{{{{{}时重新遍历子节点。 1}}。
答案 1 :(得分:1)
总的来说,你的代码很好(你知道,因为它有效),但我对改进有一些评论:
evaluation_function :您根本不使用maxHeight
。使用它或删除参数。该函数改变当前节点的父节点是一种奇怪的(一种不好的做法)。它应该查看子项的值(如果不是叶子),并根据它更新当前节点的值。此外,您可以添加一个字段来跟踪最佳子项(甚至是选定的叶子路径),以避免print
_最佳匹配过程。
print_optimal():如果2个孩子具有相同的值,则您当前遇到问题:您将打印这两个孩子并浏览这两个树。检查if (child.value < minValue) { minValue = child.value; }
是没用的,因为您认为自己已经使用过evaluation_function()
,并且仅仅取代&#34; evaluation_function
如果您忘记这样做了。