使用DFS解决8数码问题

我正在寻找Java代码,用于实现8数码游戏的深度优先搜索(DFS)和广度优先搜索(BFS),给定初始状态如下:

1 2 38 0 47 6 5

和目标状态

2 8 10 4 37 6 5

我需要打印从初始状态到目标状态的解路径(尚未完成)

这是我目前的代码。我到目前为止只能实现DFS。我的程序目前的功能是在找到目标状态时输出SUCCESS。然而,它从未达到这一步。

有人能告诉我我哪里做错了么?


回答:

好的,你的程序运行时间比预期的长。首先,我们需要找出它是陷入了无限循环,还是只是运行得慢。为了做到这一点,让我们通过在主循环中添加以下代码来让程序打印其进度:

    int statesVisited = 0;    while (OPEN.empty() == false && STATE == false) {        statesVisited++;        System.out.println(statesVisited);

然后我们看到程序每秒访问几千个状态。由于我们的处理器每秒执行几十亿条指令,这意味着处理一个状态大约需要一百万条CPU指令。这不应该这么高,对吗?那么是什么导致了这一点呢?

一般来说,我们现在会使用性能分析器来测量代码中花费了多少时间,但由于程序很短,我们可以先尝试猜测。我的第一个猜测是打印我们访问的每个状态可能非常昂贵。为了验证这一点,让我们每1000个状态打印一次:

    while (OPEN.empty() == false && STATE == false) {        statesVisited++;        if (statesVisited % 1000 == 0) {            System.out.println(statesVisited);        }

有了这个变化,我们注意到前5000个状态在不到一秒内被访问,因此打印确实很重要。我们还注意到一些奇怪的事情:虽然前5000个状态在不到一秒内被访问,但不知为何程序似乎变得越来越慢。在访问了20000个状态时,访问1000个状态大约需要一秒,而且情况越来越糟。这出乎意料,因为处理一个状态不应该变得越来越昂贵。所以我们知道循环中的某个操作变得越来越昂贵。让我们回顾一下我们的代码,以确定可能是哪个操作。

推入和弹出操作无论集合大小如何都是常数时间。但你还使用了Stack.search和LinkedList.contains。这两个操作都记录需要遍历整个堆栈或列表。所以,让我们输出这些集合的大小:

        if (statesVisited % 1000 == 0) {            System.out.println(statesVisited);            System.out.println(OPEN.size());            System.out.println(CLOSED.size());            System.out.println();        }

稍等一会儿后,我们看到:

400002594739999

所以OPEN包含25000个元素,而CLOSED接近40000个。这就解释了为什么处理一个状态变得越来越慢。因此,我们需要选择具有更高效的contains操作的数据结构,比如java.util.HashSetjava.util.LinkedHashSet(这是一个哈希集和链表的混合体,允许我们按添加顺序检索元素)。这样做,我们得到:

public static LinkedHashSet<String> OPEN = new LinkedHashSet<String>();public static HashSet<String> CLOSED = new HashSet<String>();public static boolean STATE = false;public static void main(String args[]) {    int statesVisited = 0;    String start = "123804765";    String goal = "281043765";    String X = "";    String temp = "";    OPEN.add(start);    while (OPEN.isEmpty() == false && STATE == false) {        X = OPEN.iterator().next();        OPEN.remove(X);        int pos = X.indexOf('0'); // get position of ZERO or EMPTY SPACE        if (X.equals(goal)) {            System.out.println("SUCCESS");            STATE = true;        } else {            // generate children            CLOSED.add(X);            temp = up(X, pos);            if (!(temp.equals("-1")))                OPEN.add(temp);            temp = left(X, pos);            if (!(temp.equals("-1")))                OPEN.add(temp);            temp = down(X, pos);            if (!(temp.equals("-1")))                OPEN.add(temp);            temp = right(X, pos);            if (!(temp.equals("-1")))                OPEN.add(temp);        }    }}/* * MOVEMENT UP */public static String up(String s, int p) {    String str = s;    if (!(p < 3)) {        char a = str.charAt(p - 3);        String newS = str.substring(0, p) + a + str.substring(p + 1);        str = newS.substring(0, (p - 3)) + '0' + newS.substring(p - 2);    }    // Eliminates child of X if its on OPEN or CLOSED    if (!OPEN.contains(str) && CLOSED.contains(str) == false)        return str;    else        return "-1";}/* * MOVEMENT DOWN */public static String down(String s, int p) {    String str = s;    if (!(p > 5)) {        char a = str.charAt(p + 3);        String newS = str.substring(0, p) + a + str.substring(p + 1);        str = newS.substring(0, (p + 3)) + '0' + newS.substring(p + 4);    }    // Eliminates child of X if its on OPEN or CLOSED    if (!OPEN.contains(str) && CLOSED.contains(str) == false)        return str;    else        return "-1";}/* * MOVEMENT LEFT */public static String left(String s, int p) {    String str = s;    if (p != 0 && p != 3 && p != 7) {        char a = str.charAt(p - 1);        String newS = str.substring(0, p) + a + str.substring(p + 1);        str = newS.substring(0, (p - 1)) + '0' + newS.substring(p);    }    // Eliminates child of X if its on OPEN or CLOSED    if (!OPEN.contains(str) && CLOSED.contains(str) == false)        return str;    else        return "-1";}/* * MOVEMENT RIGHT */public static String right(String s, int p) {    String str = s;    if (p != 2 && p != 5 && p != 8) {        char a = str.charAt(p + 1);        String newS = str.substring(0, p) + a + str.substring(p + 1);        str = newS.substring(0, (p + 1)) + '0' + newS.substring(p + 2);    }    // Eliminates child of X if its on OPEN or CLOSED    if (!OPEN.contains(str) && CLOSED.contains(str) == false)        return str;    else        return "-1";}public static void print(String s) {    System.out.println(s.substring(0, 3));    System.out.println(s.substring(3, 6));    System.out.println(s.substring(6, 9));    System.out.println();}

这几乎立即打印出”SUCCESS”。

Related Posts

L1-L2正则化的不同系数

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

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

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

f1_score metric in lightgbm

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

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

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

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

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

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

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

发表回复

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