每天刷個演算法題20160526:BFS解決八數碼問題(九宮格問題)

小飛_Xiaofei發表於2016-05-28

版權所有。所有權利保留。

歡迎轉載,轉載時請註明出處:

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;
        }
    }
}


相關文章