广度优先搜索算法不起作用导致无限循环

我在尝试进行广度优先搜索(BFS),在搜索状态空间时动态创建图的节点。我按照书上的方法做了,但它不起作用,前沿队列一直在运行,而已探索集合始终停留在初始值。请帮帮我,我已经卡在这里4天了。还是一个初学者程序员。

问题类

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace Test{    internal class Problem    {        public State start { get; set; }        public State end { get; set; }        public string[] action = { "UP", "LEFT", "DOWN", "RIGHT" };        public Problem(State x, State y)        {            start = x;            end = y;        }        public State Result(State s , string a)        {            State up;            if (a == "UP" && s.X - 1 >= 0)            {                 up = new State(s.X - 1, s.Y);                           }            else if (a == "LEFT" && s.Y - 1 >= 0)            {                up = new State(s.X, s.Y-1);                            }            else if (a == "DOWN" && s.X + 1 <  5)            {                up = new State(s.X, s.Y+1);                           }            else if( a == "RIGHT" && s.Y + 1 < 11)            {                up = new State(s.X + 1, s.Y);                            }                       return up;                   }             public bool GoalTest(Node<State> goal)        {            if (goal.Data.Equals(end))            {                return true;            }            return false;        }        }}

搜索类

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace Test{    internal class Search    {        public void BFS(Problem p)        {            Queue<Node<State>> frontier = new Queue<Node<State>>();            HashSet<string> explored = new HashSet<string>();            List<Node<State>> nNodes = new List<Node<State>>();            Node<State> root = new Node<State>() {Data = p.start,};            frontier.Enqueue(root);            while(frontier.Count > 0)            {                Node<State> next = frontier.Dequeue();                if(!explored.Add(next.Data.Data)) continue;                               next.Children = new List<Node<State>>();                foreach(string action in p.action)                {                    next.Children.Add(new Node<State>() { Data = p.Result(next.Data, action), Parent = next });                }                for(int i = 0; i < next.Children.Count; i++)                {                                            if (p.GoalTest(next.Children[i]) == true)                        {                            //Solution(next.Children[i]);                            break;                        }                        frontier.Enqueue(next.Children[i]);                                    }            }        }        public void Solution(Node<State> n)        {            while(n.Parent != null)            {                Console.WriteLine(n.Parent.Data);            }        }    }}

节点类

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace Test{    internal class Node<T>    {        public T Data { get; set; }        public Node<T>? Parent { get; set; }        public List<Node<T>> Children { get; set; }    }}

状态类

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace Test{    internal class State    {        public int X { get; set; }        public int Y { get; set; }        public string Data { get; }        public State(int x, int y)        {            X = x;            Y = y;            Data = $"{X}-{Y}";        }    }}

主程序

using Test;State start = new State(0, 1);State end = new State(3, 7);Problem p = new Problem(start, end);Search s = new Search();s.BFS(p);

这实际上是我的作业,所以我命名为test。
我正在尝试实现这里的伪代码:(第82页)https://zoo.cs.yale.edu/classes/cs470/materials/aima2010.pdf

更新
现在它不会卡住了,但循环运行后它不会在控制台输入任何内容,它应该通过“Parent属性”获取目标节点和起始节点之间的链接。


回答:

你从未检查节点是否已经被探索过,因此你可能会进入无限循环:

explored.Add(next.Data.Data);

应该改为

if(!explored.Add(next.Data.Data)) continue;

但代码中可能还有其他问题。我强烈推荐阅读Eric Lippert的文章如何调试小程序,因为像这样的问题应该很容易通过调试器自己找到并修复。学习如何使用调试器是一项非常宝贵的技能,会使故障排除变得更加容易。

我还建议从你的程序中删除所有字符串。相反,你应该创建一个表示坐标的类型,即一个Point或vector2Int。我建议将其制作成一个只读结构,并添加ToString重载,IEquality<Point>实现,添加减法、相等性等运算符。这种类型可以用于表示状态,也可以用于表示偏移量。这种类型可以重复用于各种不同的项目中。

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注