c九宫重排_九宫重排java

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

我们把第一个图的局面记为:12345678.

把第二个图的局面记为:123.46758

显然是按从上到下,从左到右的顺序记录数字,空格记为句点。

本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。 输入格式   输入第一行包含九宫的初态,第二行包含九宫的终态。 输出格式   输出最少的步数,如果不存在方案,则输出-1。 样例输入 12345678.

123.46758 样例输出 3 样例输入 13524678.

46758123. 样例输出 22

题解:

1.刚看到这道题,感觉可以用dfs,写了代码之后发现有一个问题,搜索的终点是什么?所以dfs只能预估最大步数max,然后搜索,但是是盲目得搜索到最大步数max,复杂度非常高。

2.后来改用bfs,每次走一步,将所有的状态记录下来,如果这种状态之前出现过,就放弃这条搜索路径,直到找到最终的状态。这种做法虽然较dfs有优化,但是大部分的搜索路径依然是盲目的。

3.最后看了别人的一些博客,发现这题可以用A*算法,关于A*算法怎么做,在这里就不说了,虽然想法比较简单,但是实现起来比较复杂,在这里就不说了。 4.下面给出bfs方法的java代码:

package 真题;

import java.util.HashMap;

import java.util.HashSet;

import java.util.LinkedList;

import java.util.Queue;

import java.util.Scanner;

public class 九宫重排精简版 {

public static void main(String[] args) {

Palace palace = new Palace();

}

}

class Palace{

String start;//初始字符串

String end;//目标字符串

int result=-1;//最终结果

public Palace(){

Scanner sca = new Scanner(System.in);

start = sca.next();

end = sca.next();

HashSet query = new HashSet<>();//hashSet用于快速查找

HashMap memery = new HashMap<>();//用于保存之前状态,key代表状态字符串,value代表到key状态所用的最小步数

Queue process = new LinkedList();//bfs用到的队列

memery.put(start,0);//放入初始字符串

query.add(start);

process.offer(start);//放入初始字符串

while(result==-1){//当没有搜索到结果是继续搜索

String cur = process.poll();

int tmp = 0;

while(cur.charAt(tmp)!='.'){

tmp++;

}

int[] d = {-3,3,-1,1};//方向数组,分别表示上下左右

for(int i=0;i<4;i++){

int p = tmp+d[i];

if(!(p<0||p>8||(p%3!=tmp%3&&p/3!=tmp/3))){

String change = cur.replace('.', '*');//交换String中的两个字符,借助中间字符‘*’

change = change.replace(cur.charAt(p),'.');

change = change.replace('*',cur.charAt(p));

if(change.equals(end)){//找到了目标状态

result = memery.get(cur)+1;

}

if(!query.contains(change)){//如果之前没有这种状态

query.add(change);

memery.put(change,memery.get(cur)+1);

process.add(change);//存入队列

}

}

}

}

System.out.println(result);

}

}

以上是第一次的代码,过了60分,然后对其进行了一些代码上的优化,最终100:

优化的内容: 1.对hashmap进行了预容量设置 2.去掉hashset 3.对if语句进行优化(对于越行问题,只会出现在2–>3,3–>2,5–>6,6–>5这四组中,所以简化为p*tmp!=6&&p*tmp!=30即可) 以下是最终代码:

package 真题;

import java.util.HashMap;

import java.util.LinkedList;

import java.util.Queue;

import java.util.Scanner;

public class 九宫重排精简版 {

public static void main(String[] args) {

Palace palace = new Palace();

}

}

class Palace{

String start;//初始字符串

String end;//目标字符串

int result=-1;//最终结果

public Palace(){

Scanner sca = new Scanner(System.in);

start = sca.next();

end = sca.next();

//HashSet query = new HashSet<>(1000000);//hashSet用于快速查找

HashMap memery = new HashMap<>(100000);//用于保存之前状态,key代表状态字符串,value代表到key状态所用的最小步数

Queue process = new LinkedList();//bfs用到的队列

memery.put(start,0);//放入初始字符串

process.offer(start);//放入初始字符串

while(result==-1){//当没有搜索到结果是继续搜索

String cur = process.poll();

int tmp = 0;

while(cur.charAt(tmp)!='.'){

tmp++;

}

int[] d = {-3,3,-1,1};//方向数组,分别表示上下左右

for(int i=0;i<4;i++){

int p = tmp+d[i];

int chengji = tmp*p;

if(p>-1&&p<9&&chengji!=6&&chengji!=30){//2-->3,3-->2,5-->6,6-->5跨行了,要去掉

String change = cur;

char c = cur.charAt(p);

change = cur.replace('.', '*');//交换String中的两个字符,借助中间字符‘*’

change = change.replace(c,'.');

change = change.replace('*',c);

if(change.equals(end)){//找到了目标状态

result = memery.get(cur)+1;

}

if(!memery.containsKey(change)){//如果之前没有这种状态

memery.put(change,memery.get(cur)+1);

process.add(change);//存入队列

}

}

}

}

System.out.println(result);

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
九宫重排是一种经典的数学问题,也被称为八数码问题。具体来说,给定一个3x3的棋盘,上面放置了1-8的数字和一个空格,要求通过交换数字和空格的位置来使得棋盘上的数字按照从左到右、从上到下的顺序排列,空格在最后一个位置。下面是一个简单的Java实现: ```java import java.util.Arrays; public class Puzzle { private int[][] board; private int row; private int col; public Puzzle(int[][] board) { this.board = board; // 找到空格的位置 for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (board[i][j] == 0) { row = i; col = j; return; } } } } public boolean move(int direction) { // 根据方向计算空格的新位置 int newRow = row; int newCol = col; switch (direction) { case 0: // 上 newRow--; break; case 1: // 下 newRow++; break; case 2: // 左 newCol--; break; case 3: // 右 newCol++; break; default: return false; } // 判断新位置是否合法 if (newRow < 0 || newRow >= 3 || newCol < 0 || newCol >= 3) { return false; } // 交换数字和空格的位置 board[row][col] = board[newRow][newCol]; board[newRow][newCol] = 0; row = newRow; col = newCol; return true; } public boolean isSolved() { // 判断棋盘是否已经解决 int[] flatBoard = Arrays.stream(board).flatMapToInt(Arrays::stream).toArray(); for (int i = 0; i < flatBoard.length - 1; i++) { if (flatBoard[i] != i + 1) { return false; } } return true; } } ``` 在这个实现中,我们用一个二维数组来表示九宫格,其中0表示空格。在Puzzle类的构造函数中,我们找到空格的位置,并将其记录在成员变量row和col中。在move方法中,我们根据方向计算出空格的新位置,然后判断这个位置是否合法。如果合法,我们就将数字和空格的位置互换,并更新row和col的值。在isSolved方法中,我们将棋盘展开成一维数组,并检查其中的数字是否按照从左到右、从上到下的顺序排列,空格在最后一个位置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值