每天刷个算法题20160526:BFS解决八数码问题(九宫格问题)

Posted 小飞_Xiaofei

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了每天刷个算法题20160526:BFS解决八数码问题(九宫格问题)相关的知识,希望对你有一定的参考价值。

版权所有。所有权利保留。

欢迎转载,转载时请注明出处:

http://blog.csdn.net/xiaofei_it/article/details/51524864


为了防止思维僵化,每天刷个算法题。已经刷了几天了,现在发点代码。

我已经建了一个开源项目,每天的题目都在里面:

https://github.com/Xiaofei-it/Algorithms

绝大部分算法都是我自己写的,没有参考网上通用代码。读者可能会觉得有的代码晦涩难懂,因为那是我自己的理解。

最近几天都是在写一些原来的东西,大多数是非递归。以后准备刷点DP、贪心之类的题。

下面是BFS解决八数码问题,这个其实应该用A*算法,但我今天练一下BFS,以后再写一个A*的版本。

/**
 *
 * Copyright 2016 Xiaofei
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package xiaofei.algorithm;

import java.util.ArrayList;
import java.util.HashSet;

/**
 * Created by Xiaofei on 16/5/26.
 *
 * 八数码问题,也就是九宫格问题。按理说要用A*算法,这个很久以前写过。我以后再写。
 *
 * 今天只是想练练BFS。
 *
 * 这个英文不知道该怎么说,Eight digit maze是我自己瞎写的。
 *
 * 9的9次方,可以用int表示。int是4字节。
 *
 * 如果用其他方式表示,比如一个字节表示两个格,好像都没int省空间。
 *
 * 所以就用int。
 */
public class EightDigitMaze {

    private static int[] dx = new int[]{0, 0, -1, 1};

    private static int[] dy = new int[]{-1, 1, 0, 0};

    private static int arrayToInt(int[][] array) {
        int result = 1;
        for (int i = 0; i < 3; ++i) {
            final int[] subArray = array[i];
            for (int j = 0; j < 3; ++j) {
                result = result * 9 + subArray[j];
            }
        }
        return result;
    }

    private static int[][] intToArray(int x) {
        int[][] result = new int[3][3];
        for (int i = 2; i >= 0; --i) {
            for (int j = 2; j >= 0; --j) {
                result[i][j] = x % 9;
                x /= 9;
            }
        }
        return result;
    }

    private static void output(int x) {
        int[][] array = intToArray(x);
        for (int i = 0; i < 3; ++i) {
            for (int j = 0; j < 3; ++j) {
                if (array[i][j] == 0) {
                    System.out.print(' ');
                } else {
                    System.out.print(array[i][j]);
                }
            }
            System.out.println();
        }
    }

    /**
     *
     * 下面这个函数很长,因为我把所有的东西都放里面了。为什么不变成子函数?因为变成子函数的话很蛋疼。
     *
     * 我这个项目都是算法,不是工程,所以不用管那么多代码风格。
     */
    public static void solve(int[][] source, int[][] dest) {
        class Element {
            int state;
            int last;
            Element(int state) {
                this.state = state;
                this.last = -1;
            }
            Element(int state, int last) {
                this.state = state;
                this.last = last;
            }
        }
        HashSet<Integer> set = new HashSet<>();
        final int sourceInt = arrayToInt(source);
        final int destInt = arrayToInt(dest);
        set.add(sourceInt);
        //如果用Queue,我不知道怎么保存之前的数据,所以这里直接用ArrayList
        ArrayList<Element> queue = new ArrayList<>();
        int head = 0;
        int tail = 1;
        queue.add(new Element(sourceInt));

        while (head < tail) {

            Element element = queue.get(head);

            if (element.state == destInt) {
                //输出结果,退出循环。
                ArrayList<Integer> tmp = new ArrayList<>();
                int index = head;
                while (index != -1) {
                    tmp.add(index);
                    index = queue.get(index).last;
                }
                final int size = tmp.size();
                for (int i = size - 1; i >= 0; --i) {
                    System.out.println("Step " + Integer.toString(size - i));
                    output(queue.get(tmp.get(i)).state);
                }
                break;
            }

            int[][] array = intToArray(element.state);
            boolean flag = false;
            int x = -1, y = -1;
            for (int i = 0; i < 3; ++i) {
                for (int j = 0; j < 3; ++j) {
                    if (array[i][j] == 0) {
                        flag = true;
                        x = i;
                        y = j;
                        break;
                    }
                }
                if (flag) {
                    break;
                }
            }

            for (int i = 0; i < 4; ++i) {
                int nextX = x + dx[i];
                int nextY = y + dy[i];
                if (0 <= nextX && nextX <= 2 && 0 <= nextY && nextY <= 2) {
                    int tmp = array[nextX][nextY];
                    array[nextX][nextY] = 0;
                    array[x][y] = tmp;
                    int state = arrayToInt(array);
                    if (!set.contains(state)) {
                        queue.add(new Element(state, head));
                        set.add(state);
                        ++tail;
                    }
                    array[nextX][nextY] = tmp;
                    array[x][y] = 0;
                }
            }

            ++head;
        }
    }
}


以上是关于每天刷个算法题20160526:BFS解决八数码问题(九宫格问题)的主要内容,如果未能解决你的问题,请参考以下文章

每天刷个算法题20160526:BFS解决八数码问题(九宫格问题)

每天刷个算法题20160519:回溯法解八皇后

每天刷个算法题20160519:回溯法解八皇后

每天刷个算法题20160519:回溯法解八皇后

[A*] aw179. 八数码(A*+bfs最小步数模型+模板题)

算法BFS+哈希解决八数码问题