第四届蓝桥杯决赛题-九宫重排(双向广搜).java

问题描述
  如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。

  我们把第一个图的局面记为:12345678.
  把第二个图的局面记为:123.46758
  显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
  本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入格式
  输入第一行包含九宫的初态,第二行包含九宫的终态。
输出格式
  输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
样例输出
3
样例输入
13524678.
46758123.
样例输出
22

/*
 * 132757	张燚	九宫重排	  2014-03-08 21:56	5.209KB	JAVA	正确	 100	156ms	33.90MB	评测详情  
 * 
 * 
 */
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;
public class Main{//双向广搜
	private static HashMap<String,Integer> hm1=null,hm2=null;
	public static void main(String[] args) {
		BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
		try {
			String start=bf.readLine();
			String end=bf.readLine();
			char a[][]=new char[3][3];
			char b[][]=new char[3][3];
			int c=0;
			int x1=0,y1=0,x2=0,y2=0;
			for(int i=0;i<3;i++){
				for(int j=0;j<3;j++){
					a[i][j]=start.charAt(c);
					b[i][j]=end.charAt(c);
					if(a[i][j]=='.'){
						x1=i;
						y1=j;
					}
					if(b[i][j]=='.'){
						x2=i;
						y2=j;
					}
					c++;
				}
			}
			Node node1=new Node(a,0,x1,y1);
			Node node2=new Node(b,0,x2,y2);
			Queue<Node> q1=new LinkedList<Node>();
			Queue<Node> q2=new LinkedList<Node>();
			hm1=new HashMap<String, Integer>();
			hm2=new HashMap<String, Integer>();
			hm1.put(start, 0);
			hm2.put(end, 0);
			q1.add(node1);
			q2.add(node2);
			System.out.println(bfs(q1,q2));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	private static int bfs(Queue<Node> q1,Queue<Node> q2) {
		while(!q1.isEmpty()||!q2.isEmpty()){
			if(!q1.isEmpty()){
				
				Node node1=q1.poll();
			//	System.out.println(node1.getTuString()+"----1");
				if(hm2.containsKey(node1.getTuString())){
					return node1.getSum()+hm2.get(node1.getTuString());
				}
				int x=node1.getX();
				int y=node1.getY();
				if(x>0){
					char a[][]=node1.getTuCopy();
					a[x][y]=a[x-1][y];
					a[x-1][y]='.';
					Node n=new Node(a,node1.getSum()+1,x-1,y);
					String s=n.getTuString();
					if(hm2.containsKey(s)){
						return n.getSum()+hm2.get(s);
					}
					if(!hm1.containsKey(s)){
						hm1.put(s, n.getSum());
						q1.add(n);
					}
				}
				if(x<2){
					char a[][]=node1.getTuCopy();
					a[x][y]=a[x+1][y];
					a[x+1][y]='.';
					Node n=new Node(a,node1.getSum()+1,x+1,y);
					String s=n.getTuString();
					if(hm2.containsKey(s)){
						return n.getSum()+hm2.get(s);
					}
					if(!hm1.containsKey(s)){
						hm1.put(s, n.getSum());
						q1.add(n);
					}
				}
				if(y>0){
					char a[][]=node1.getTuCopy();
					a[x][y]=a[x][y-1];
					a[x][y-1]='.';
					Node n=new Node(a,node1.getSum()+1,x,y-1);
					String s=n.getTuString();
					if(hm2.containsKey(s)){
						return n.getSum()+hm2.get(s);
					}
					if(!hm1.containsKey(s)){
						hm1.put(s, n.getSum());
						q1.add(n);
					}
				}
				if(y<2){
					char a[][]=node1.getTuCopy();
					a[x][y]=a[x][y+1];
					a[x][y+1]='.';
					Node n=new Node(a,node1.getSum()+1,x,y+1);
					String s=n.getTuString();
					if(hm2.containsKey(s)){
						return n.getSum()+hm2.get(s);
					}
					if(!hm1.containsKey(s)){
						hm1.put(s, n.getSum());
						q1.add(n);
					}
				}
			}
			
			
			if(!q2.isEmpty()){
				
				Node node2=q2.poll();
			//	System.out.println(node2.getTuString()+"----2");
				if(hm1.containsKey(node2.getTuString())){
					return node2.getSum()+hm1.get(node2.getTuString());
				}
				int x=node2.getX();
				int y=node2.getY();
				if(x>0){
					char a[][]=node2.getTuCopy();
					a[x][y]=a[x-1][y];
					a[x-1][y]='.';
					Node n=new Node(a,node2.getSum()+1,x-1,y);
					String s=n.getTuString();
					if(hm1.containsKey(s)){
						return n.getSum()+hm1.get(s);
					}
					if(!hm2.containsKey(s)){
						hm2.put(s, n.getSum());
						q2.add(n);
					}
				}
				if(x<2){
					char a[][]=node2.getTuCopy();
					a[x][y]=a[x+1][y];
					a[x+1][y]='.';
					Node n=new Node(a,node2.getSum()+1,x+1,y);
					String s=n.getTuString();
					if(hm1.containsKey(s)){
						return n.getSum()+hm1.get(s);
					}
					if(!hm2.containsKey(s)){
						hm2.put(s, n.getSum());
						q2.add(n);
					}
				}
				if(y>0){
					char a[][]=node2.getTuCopy();
					a[x][y]=a[x][y-1];
					a[x][y-1]='.';
					Node n=new Node(a,node2.getSum()+1,x,y-1);
					String s=n.getTuString();
					if(hm1.containsKey(s)){
						return n.getSum()+hm1.get(s);
					}
					if(!hm2.containsKey(s)){
						hm2.put(s, n.getSum());
						q2.add(n);
					}
				}
				if(y<2){
					char a[][]=node2.getTuCopy();
					a[x][y]=a[x][y+1];
					a[x][y+1]='.';
					Node n=new Node(a,node2.getSum()+1,x,y+1);
					String s=n.getTuString();
					if(hm1.containsKey(s)){
						return n.getSum()+hm1.get(s);
					}
					if(!hm2.containsKey(s)){
						hm2.put(s, n.getSum());
						q2.add(n);
					}
				}
			}
		}
		return -1;
	}
}
class Node{
	char tu[][]=new char[3][3];
	int sum=0;
	int x=0,y=0;
	public Node(char[][] tu, int sum, int x, int y) {
		super();
		this.tu = tu;
		this.sum = sum;
		this.x = x;
		this.y = y;
	}
	public char[][] getTuCopy() {
		char a[][]=new char[3][3];
		for(int i=0;i<3;i++)
			for(int j=0;j<3;j++)
				a[i][j]=tu[i][j];
		return a;
	}
	public String getTuString() {
		StringBuffer sb=new StringBuffer("");
		for(int i=0;i<3;i++)
			for(int j=0;j<3;j++)
				sb.append(tu[i][j]);
		return sb.toString();
	}
	public void setTu(char[][] tu) {
		this.tu = tu;
	}
	public int getSum() {
		return sum;
	}
	public void setSum(int sum) {
		this.sum = sum;
	}
	public int getX() {
		return x;
	}
	public void setX(int x) {
		this.x = x;
	}
	public int getY() {
		return y;
	}
	public void setY(int y) {
		this.y = y;
	}
}




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
好的,以下是使用Java编写的A*算法实现八数码难的搜索的示例代码: ``` import java.util.*; public class EightPuzzleSolver { // 表示八数码难的矩阵 private int[][] board; // 初始状态 private int[][] initialBoard = { {2, 8, 3}, {1, 6, 4}, {7, 0, 5} }; // 目标状态 private int[][] targetBoard = { {1, 2, 3}, {8, 0, 4}, {7, 6, 5} }; // 启发函数类型 private static final int MANHATTAN_DISTANCE = 1; private static final int MISPLACED_TILES = 2; // 启发函数类型,默认为曼哈顿距离 private int heuristicType = MANHATTAN_DISTANCE; // 构造函数 public EightPuzzleSolver() { this.board = initialBoard; } // 构造函数 public EightPuzzleSolver(int[][] board) { this.board = board; } // 设置启发函数类型 public void setHeuristicType(int type) { this.heuristicType = type; } // 获取启发函数类型 public int getHeuristicType() { return heuristicType; } // 获取当前状态的深度 private int getDepth(int[][] board) { int depth = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (board[i][j] != 0) { depth++; } } } return depth; } // 计算曼哈顿距离 private int calculateManhattanDistance(int[][] board) { int distance = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (board[i][j] != 0) { int row = (board[i][j] - 1) / 3; int col = (board[i][j] - 1) % 3; distance += Math.abs(row - i) + Math.abs(col - j); } } } return distance; } // 计算错位数 private int calculateMisplacedTiles(int[][] board) { int count = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (board[i][j] != 0 && board[i][j] != targetBoard[i][j]) { count++; } } } return count; } // 计算启发函数值 private int calculateHeuristicValue(int[][] board) { switch (heuristicType) { case MANHATTAN_DISTANCE: return calculateManhattanDistance(board); case MISPLACED_TILES: return calculateMisplacedTiles(board); default: return 0; } } // 判断当前状态是否为目标状态 private boolean isGoalState(int[][] board) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (board[i][j] != targetBoard[i][j]) { return false; } } } return true; } // 交换两个位置的值 private void swap(int[][] board, int row1, int col1, int row2, int col2) { int temp = board[row1][col1]; board[row1][col1] = board[row2][col2]; board[row2][col2] = temp; } // 生成后继状态 private List<int[][]> generateSuccessors(int[][] board) { List<int[][]> successors = new ArrayList<>(); int row = -1, col = -1; // 找到空格的位置 for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (board[i][j] == 0) { row = i; col = j; break; } } } // 向上移动空格 if (row > 0) { int[][] successor = new int[3][3]; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { successor[i][j] = board[i][j]; } } swap(successor, row, col, row - 1, col); successors.add(successor); } // 向下移动空格 if (row < 2) { int[][] successor = new int[3][3]; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { successor[i][j] = board[i][j]; } } swap(successor, row, col, row + 1, col); successors.add(successor); } // 向左移动空格 if (col > 0) { int[][] successor = new int[3][3]; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { successor[i][j] = board[i][j]; } } swap(successor, row, col, row, col - 1); successors.add(successor); } // 向右移动空格 if (col < 2) { int[][] successor = new int[3][3]; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { successor[i][j] = board[i][j]; } } swap(successor, row, col, row, col + 1); successors.add(successor); } return successors; } // A*算法求解八数码难 public List<int[][]> solve() { // 初始化priority queue PriorityQueue<Node> pq = new PriorityQueue<>(); // 将初始状态加入priority queue pq.add(new Node(board, null, 0, calculateHeuristicValue(board))); // 初始化visited set Set<String> visited = new HashSet<>(); visited.add(Arrays.deepToString(board)); // 进行搜索 while (!pq.isEmpty()) { // 取出f(n)最小的状态 Node node = pq.poll(); // 判断是否为目标状态 if (isGoalState(node.board)) { // 构造路径 List<int[][]> path = new ArrayList<>(); while (node.parent != null) { path.add(node.board); node = node.parent; } path.add(node.board); Collections.reverse(path); return path; } // 生成后继状态 List<int[][]> successors = generateSuccessors(node.board); for (int[][] successor : successors) { // 判断后继状态是否已经访问过 if (!visited.contains(Arrays.deepToString(successor))) { // 计算g(n)和h(n) int g = node.g + 1; int h = calculateHeuristicValue(successor); // 加入priority queue pq.add(new Node(successor, node, g, h)); // 标记为已访问 visited.add(Arrays.deepToString(successor)); } } } // 无解 return null; } // 内部类,表示搜索树中的一个节点 private class Node implements Comparable<Node> { int[][] board; // 状态矩阵 Node parent; // 父节点 int g; // 从初始状态到达当前状态的代价 int h; // 从当前状态到达目标状态的估算代价 public Node(int[][] board, Node parent, int g, int h) { this.board = board; this.parent = parent; this.g = g; this.h = h; } // 比较两个节点的f(n)值 public int compareTo(Node other) { return (g + h) - (other.g + other.h); } } // 测试 public static void main(String[] args) { EightPuzzleSolver solver = new EightPuzzleSolver(); solver.setHeuristicType(MANHATTAN_DISTANCE); List<int[][]> path = solver.solve(); if (path != null) { for (int[][] board : path) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { System.out.print(board[i][j] + " "); } System.out.println(); } System.out.println(); } } else { System.out.println("No solution found!"); } } } ``` 在上面的代码中,我们定义了一个`EightPuzzleSolver`类,表示八数码难的求解器。在构造函数中,我们可以指定初始状态,如果不指定,则默认为: ``` 2 8 3 1 6 4 7 0 5 ``` 我们还可以使用`setHeuristicType`方法来设置启发函数类型(曼哈顿距离或错位数),默认为曼哈顿距离。 在`solve`方法中,我们实现了A*算法的框架,包括初始化priority queue和visited set,取出f(n)最小的状态,判断是否为目标状态,生成后继状态,计算g(n)和h(n),加入priority queue和visited set等操作。 在`generateSuccessors`方法中,我们实现了生成后继状态的函数,具体实现方式为向上、下、左、右四个方向移动空格,生成四个后继状态。 在`Node`类中,我们定义了搜索树中的一个节点,表示一个状态,其中包括状态矩阵、父节点、从初始状态到达当前状态的代价和从当前状态到达目标状态的估算代价。我们还实现了`compareTo`方法,用于比较两个节点的f(n)值,以便在priority queue中进行排序。 最后,在`main`方法中,我们创建了一个`EightPuzzleSolver`对象,设置了启发函数类型为曼哈顿距离,并调用`solve`方法求解八数码难。如果求解成功,则输出求解路径,否则输出"No solution found!"。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值