Topic 2: Implicit graph search problem (experiment preparation)

Experiment content

  • For the Jiugong rearrangement problem, establish a heuristic search solution method for graphs;
  • Use the A* algorithm to solve the Jiugong rearrangement problem.

Experimental requirements

3х3 Jiugong chessboard, place 8 chess pieces with numbers 1~8, there is a space in the chessboard, and the chess pieces around the space can be moved into the space to change the layout of the chessboard. According to the given initial layout and target layout, move the pieces from the initial layout to the target layout, solve the moving steps and output. Please design an algorithm and use a suitable search strategy to find the shortest path with less space and time costs.

Insert picture description here

Choice of programming language

  • Programming language: Java
  • Compilation environment: JDK1.8
  • Development tools: IntelliJ IDEA

Project idea

Project analysis

(1) Eight numbers from 1 to 8 are randomly distributed in a nine-square grid.
(2) There is a non-digit grid (called a space) in the nine-square grid. For the convenience of calculation, you can use # to replace
(3) Several numbers around the space can be combined with The space swap position
(4) has been swapped many times, making it important that the space is located in the nine-square grid. The numbers 1-8 start from the upper-left grid and are arranged in clockwise order.
(5) From the initial state to the final state after multiple exchanges. Countless possibilities, find the optimal algorithm

Algorithm selection

A* algorithm

A* algorithm, A* (A-Star) algorithm is the most effective direct search method for solving the shortest path in a static road network, and it is also an effective algorithm for solving many search problems. The closer the estimated distance value in the algorithm is to the actual value, the faster the final search speed.
Note-it is the most effective direct search algorithm. After that, many preprocessing algorithms (such as ALT, CH, HL, etc.) have emerged, and the online query efficiency is thousands or even tens of thousands of times that of the A* algorithm.
The formula is expressed as: f(n)=g(n)+h(n),
where f(n) is the cost estimate from the initial state to the target state through the state n, and
g(n) is the cost estimate from the initial state in the state space The actual cost
from state to state n, h(n) is the estimated cost of the best path from state n to the target state.
(For the path search problem, the state is the node in the graph, and the cost is the distance)
The selection of h(n) ensures that the shortest path (the optimal solution) condition is found, and the key lies in the selection of the evaluation function f(n) (or h( n) selection).
We use d(n) to express the distance from state n to the target state, then the selection of h(n) roughly has the following three situations:
(1) If h(n)<d(n) the actual distance to the target state, this In this case, the number of search points is large, the search range is large, and the efficiency is low. But the optimal solution can be obtained.
(2) If h(n)=d(n), that is, the estimated distance h(n) is equal to the shortest distance, then the search will strictly follow the shortest path, and the search efficiency at this time is the highest.
(3) If h(n)>d(n), the number of search points is small, the search range is small, and the efficiency is high, but the optimal solution cannot be guaranteed.

The code is implemented as follows:

public static int A_star(int[][] MT) {
    
    
        // 找到空格所在的位置
        int x0 = 0, y0 = 0;
        for (x0 = 0; x0 < N; x0++) {
    
    
            boolean flag = false;
            for (y0 = 0; y0 < N; y0++) {
    
    
                if (MT[x0][y0] == 0) {
    
    
                    flag = true;
                    break;
                }
            }
            if (flag)
                break;
        }
        // 优先队列
        Queue<node> q = new PriorityQueue<node>(cmp);
        int[][] curmt = new int[N][];
        int[][] markemt = new int[N][];
        // clone方法用于复制一个对象,在内存中开辟同样大小的空间
        for (int r = 0; r < N; r++)
            curmt[r] = MT[r].clone();
        for (int r = 0; r < N; r++)
            markemt[r] = MT[r].clone();
        List<int[][]> path = new ArrayList<int[][]>();
        // path加入初始状态
        path.add(MT);
        // 创建一个结点,表示空格,估价函数初始化为0
        node cur = new node(x0, y0, 0, 0, 0, curmt, path);
        // 将出现过的所有状态都加入marke集合中
        marke.add(markemt);
        // 入队并遍历
        q.add(cur);
        while (!q.isEmpty()) {
    
    
            // 队首元素出队
            cur = (node) q.poll().clone();
            boolean tag = false;
            // 判断当前状态是不是目标状态
            for (int i = 0; i < N; i++) {
    
    
                for (int j = 0; j < N; j++) {
    
    
                    if (cur.mt[i][j] != endMT[i][j]) {
    
    
                        tag = true;
                    }
                }
            }
            // 如果是,输出结果
            if (!tag) {
    
    
                System.out.println("共扩展了" + marke.size() + "个结点");
                return cur.step;
            }
            // 遍历四种方向上的移动
            for (int i = 0; i < 4; i++) {
    
    
                node next = (node) cur.clone();
                next.x = cur.x + dir[i][0];
                next.y = cur.y + dir[i][1];
                // 如果空格位置不合法就忽略这个状态
                if (next.x >= 0 && next.x < N && next.y >= 0 && next.y < N) {
    
    
                    // 因为上面next定义时clone了cur,所以在这里更新空格的位置
                    next.mt[cur.x][cur.y] = next.mt[next.x][next.y];
                    next.mt[next.x][next.y] = 0;
                    boolean mark = false;
                    // 判断当前状态有没有出现过
                    for (int c = 0; c < marke.size(); c++) {
    
    
                        int x = 0, y = 0;
                        for (x = 0; x < N; x++) {
    
    
                            for (y = 0; y < N; y++)
                                if (marke.get(c)[x][y] != next.mt[x][y])
                                    break;
                            if (y < N)
                                break;
                        }
                        if (x == N && y == N)
                            mark = true;
                    }
                    // 若出现过则忽略这个状态
                    if (!mark) {
    
    
                        // 更新next的属性值step和估价函数g
                        next.step++;
                        next.g++;
                        // 将当前状态加入到结点的path中,因为程序中定义结点时,clone了上一个结点,所以在当前结点添加的状态也会clone到下一个结点中。
                        next.path.add(next.mt);
                        // 计算估价函数h,获取每个位置的数字,到达目标状态中对应数字的位置,所需要的步数
                        int count = 0;
                        for (int row = 0; row < N; row++) {
    
    
                            for (int cow = 0; cow < N; cow++) {
    
    
                                if (cow != 0 && next.mt[row][cow] != endMT[row][cow]) {
    
    
                                    count += Math.abs(row - map.get(next.mt[row][cow])[0])
                                            + Math.abs(cow - map.get(next.mt[row][cow])[1]);
                                }
                            }
                        }
                        next.h = count;
                        // 将扩展状态入队
                        int[][] newmt = new int[N][];
                        for (int r = 0; r < N; r++)
                            newmt[r] = next.mt[r].clone();
                        marke.add(newmt);
                        q.add((node) next.clone());
                    }
                }
            }
        }
        return 0;
    }

Guess you like

Origin blog.csdn.net/KT_xiaobai/article/details/114265392