845. 八数码 Java代码 (bfs)

845. 八数码 Java代码 (bfs)_第1张图片

 

输入样例:

2  3  4  1  5  x  7  6  8

输出样例

19

算法思路:

通过移动x的位置,找出到达终点状态的最少次数,属于权值为1的最短路问题,用宽搜。

由于是从初始状态的图到终止状态的图,所以需要将八数码的所有状态抽象成图中的一个结点。

  • 状态表示:八数码是3x3的矩阵,可以将二维矩阵转换为一维的字符串,用字符串存储状态。
  • 记录到达每个状态的移动次数:由于不能直接用数组表示距离,所以可以用map记录,key存储每个状态,value存储到达每个状态的次数。若某个状态的value为空,则表示该状态还没有被访问过。
  • 判断从一个状态到达另一个状态:先将出队的状态转换为二维坐标,加上偏移量后再转换回一维字符串。

Java代码:

import java.io.*;
import java.util.*;

public class Main {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String[] split = br.readLine().split(" ");
		String st = "";
		for(int i = 0; i < split.length; i++)
			st += split[i];
		
		String end = "12345678x";
		System.out.println(bfs(st, end));
	}
	
	private static void swap(char arr[], int a, int b) {  //交换数组中的ab位置元素,数组为引用数据类型(引用传递)
		char t = arr[a];
		arr[a] = arr[b];
		arr[b] = t;
	}
	
	public static int bfs(String st, String end) {
		Queue qu = new LinkedList<>();
		Map map = new HashMap<>(); // 记录到达某个状态时的次数
		map.put(st, 0); // 开始状态次数为0
		qu.add(st);
		int []dx = new int[] {-1, 0, 1, 0};
		int []dy = new int[] {0, 1, 0, -1};
		
		while(!qu.isEmpty()) {
			String str = qu.poll();
			if(str.equals(end)) return map.get(str);  //到达终止状态时,返回此时次数
			
			int idx = str.indexOf('x'); //找出一维数组中x的位置
			int x = idx / 3, y = idx % 3; // 一维数组转化成二维数组
			for(int i = 0; i < 4; i++) {
				int a  = x + dx[i], b = y + dy[i];  // 加上偏移量得到新的状态
				
				if(a < 0 || a > 2 || b < 0 || b > 2) continue; // 不合法状态
				char []arr = str.toCharArray();  // 将字符串转化成数组
				swap(arr, idx, 3 * a + b);  // 改变状态
				
				String after = new String(arr);  // 再转化回去
				if(map.get(after) == null) {  // 当某个转台还没有被访问时
					map.put(after, map.get(str)+ 1);  // 将次数存储下来
					qu.add(after);  // 将这个状态入队
				}
			}
		}
		return -1;
	}
}

你可能感兴趣的:(图,搜索,最短路问题,bfs)