九宫重排问题
参考博客
https://www.cnblogs.com/soTired/p/5528099.html
这位博主采用c++实现,思路很好。但是采用bfs又递归的方式没有必要。
#include <stdio.h>
#include <string.h>
long int fac[10]={1,1,2,6,24,120,720,5040,40320,362880};//阶乘表
unsigned char step[363880]={0}; // 9!=362880,所以数组要大点
char method[4][2]={{-1,0},{0,1},{1,0},{0,-1}}; //4种移动方法
struct node_t{
unsigned char data[9];
unsigned int step_p;
};
struct node_t save_step[363880]; //保存移动数据,最多有 9!个移动数据
unsigned char end_p[9]; //终点坐标
unsigned int end_index; //记录终点位置
int congtuo(unsigned char s[],int n)
{
int i,j,temp,num;
num=0;
for(i=0;i<n;i++)
{
temp=0;
for(int j=i+1;j<n;j++)
if(s[j]<s[i]) //判断几个数小于它
temp++;
num+=fac[n-i-1]*temp;
}
return num;
}
/*处理0函数
*返回值0:交换的位置非法,或被走过
*返回值1:没被走过
*返回值2:找到终点
*/
int handler_zero(int i,unsigned char data[])
{
int x,y,temp,num;
for(int j=0;j<9;j++)
if(data[j]==0)
{
/*[x,y]:需要交换的位置*/
x=j%3+method[i][0];
y=j/3+method[i][1];
/*判断交换位置是否越界*/
if(x<0||x>2 ||y<0||y>2)
return 0;
/*判断交换后的位置是否已被走过*/
data[j]= data[x+y*3];
data[x+y*3]=0;
num=congtuo(data,9);
if(step[num]==1) //已被走过
{
return 0;
}
if(memcmp(end_p,data,9)==0) //找到终点
{
return 2;
}
step[num]=1;
return 1;
}
}
int start=0,end=0;
int bfs(void)
{
int x,y;
int next_end=end; //存放下次bfs的end标志位
int res;
unsigned char temp[9];
for(;start<=end;start++)
{
for(int i=0;i<4;i++) //4种走法
{
memcpy(temp,(unsigned char *)save_step[start].data,9); // save_step[] node数组
res=handler_zero(i,temp); //处理数据里的0
if(res) //保存数据
{
memcpy((unsigned char *)save_step[++next_end].data,temp,9);
save_step[next_end].step_p=start; //记录上次步数位置.
if(res==2) //找到终点
{
end_index=next_end; //记录终点步数位置.
return 1;
}
}
}
}
start=end+1;
end=next_end;
return (1+bfs());
}
int main()
{
int step_num=0; //步数
unsigned char s[9];
printf("please enter start point:\r\n");
for(int i=0;i<9;i++)
{
scanf("%1d",&save_step[0].data[i]);
}
printf("please enter end point:\r\n");
for(int i=0;i<9;i++)
{
scanf("%1d",&end_p[i]);
}
step_num=bfs();
printf("%d\n",step_num);
/**打印步数具体内容**/
for(;step_num>=0;step_num--)
{
printf("**step %d********\n",step_num);
for(int i=0;i<3;i++)
{
printf("%d %d %d\n",save_step[end_index].data[i*3],
save_step[end_index].data[i*3+1],
save_step[end_index].data[i*3+2]);
}
end_index=save_step[end_index].step_p;
printf("\n");
}
}
仿照博主用java实现
遇到的困难:数据结构的使用不清晰。
九宫格用一个字符串就能表示。
使用recordMapList保存走过的RecordMap使问题变得清晰了。
for循环遍历4个方向时,将当前RecordMap赋值给temp
public class JG {
private Set<String> set = new HashSet<>();
private static List<RecordMap> recordMapList = new ArrayList<>();
private static RecordMap finalRecordMap;
class RecordMap {
String data; //保存九宫格字符串
int pre_pos; //前一个路径索引
}
//left up right down
int[] dx = {-1, 0, 1, 0}, dy = {0, -1, 0, 1};
private void bfs() {
int start = 0, end = 0;
int x, y;
char[] temp = new char[9];
//记录最短路径
for (; start <= end; start++) {
for (int i = 0; i < 4; i++) {
//赋值给temp
assign(recordMapList.get(start).data, temp);
int flag = canMove(i, temp);
if (flag > 0) {
//添加temp至数组链表中
RecordMap recordMap = new RecordMap();
recordMap.data = new String(temp); //保存移动后的九宫数据
recordMap.pre_pos = start; //记录上一个位置
recordMapList.add(recordMap);
end++;
if (flag == 2) { //成功走到终点
printPath(recordMapList);
return ;
}
}
}
}
}
private void printPath(List<RecordMap> recordMapList) {
int minPathLength=0;
for(int pre=recordMapList.size()-1;pre>0;pre=recordMapList.get(pre).pre_pos){
minPathLength++;
String s=recordMapList.get(pre).data;
for(int i=0;i<s.length();i+=3){
System.out.println(s.charAt(i)+" "+s.charAt(i+1)+" "+s.charAt(i+2));
}
System.out.println("############");
}
}
private void assign(String src, char[] des) {
//赋值
for (int i = 0; i < src.length(); i++) {
if (i >= 9)
throw new RuntimeException("data值error!");
des[i] = src.charAt(i);
}
}
/**
* @param i
* @param temp
* @return 0 move失败 ; 1 成功 ; 2 找到终点
*/
private int canMove(int i, char[] temp) {
int pos = findBlankPos(temp);
int y = pos / 3 + dy[i];
int x = pos % 3 + dx[i];
//待移动的位置是否越界
if (x < 0 || x > 2 || y < 0 || y > 2)
return 0;
//更新temp
temp[pos] = temp[y * 3 + x];
temp[y * 3 + x] = '0';
if (set.contains(new String(temp))) {
return 0;
}
set.add(new String(temp));
if (new String(temp).equals(new String(finalRecordMap.data))) {
return 2;
}
return 1;
}
private int findBlankPos(char[] map) {
for (int i = 0; i < map.length; i++) {
if (map[i] == '0')
return i;
}
throw new RuntimeException("没有字符0!");
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new StringReader("283104765\n123804765"));
// Scanner scanner = new Scanner(System.in);
RecordMap recordMap = new JG().new RecordMap();
finalRecordMap = new JG().new RecordMap();
System.out.println("输入起始串:");
// recordMap.data = scanner.nextLine();
recordMap.data = br.readLine();
recordMapList.add(recordMap);
// set.add(recordMap.data); //多一条数据而已
System.out.println("输入目标串:");
finalRecordMap.data = br.readLine();
new JG().bfs();
}
}