43-八数码

题题目内容:
在3*3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局和目标布局,为了使题目简单,设目标状态为:
1 2 3
8 0 4
7 6 5
找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变.
输入描述
输入初试状态,3*3的九个数字,空格用0表示.

输出描述
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次
(若无法到达目标状态则输出-1).

输入样例
2 8 3
1 0 4
7 6 5

输出样例
4
#include <iostream>
#include <set>
#include <cstring>
using namespace std;
typedef int State[9];   		  //定义状态类型 
const int maxstate = 10000000;	 	
int goal[9]{
	1, 2, 3,
	8, 0, 4,
	7, 6, 5
};
State st[maxstate];				  //状态数组,保存所有状态	
int dist[maxstate];				  //距离数组	
								  //如果需要打印方案,可以在这里加一个"父亲编号"数组int fa[maxstatue] 
const int dx[] = {-1, 1, 0, 0};
const int dy[] = {0, 0, -1, 1};

set<int> vis;
void init_lookup_table(){
	vis.clear();
}
int try_to_insert(int s){
	int v = 0;
	for(int i = 0; i < 9; i++)
		v = v * 10 + st[s][i];
	if(vis.count(v))
		return 0;
	vis.insert(v); 
	return 1;
} 

int bfs(){						 //bfs,返回目标状态在st数组下标 
	init_lookup_table();         //初始化查找表 
	int front = 1, rear =  2;	 //不使用下标0,因为0被看作“不存在” 
	while(front < rear){ 
		State& s = st[front];   //用引用简化代码			
		if(memcmp(goal, s, sizeof(s)) == 0)
			return front;            //找到目标状态,成功返回
		int z;
		for(z = 0; z < 9; z++)		 //找到0的位置 
			if(!s[z]) 
				break;
		int x = z / 3, y = z % 3;
		for(int d = 0; d < 4; d++){
			int newx = x + dx[d];
			int newy = y + dy[d];
			int newz = newx * 3 + newy;
			if(newx >= 0 && newx < 3 && newy >= 0 && newy < 3){   //判断是否移动合法 
				State& t = st[rear];
				memcpy(&t, &s, sizeof(s));   //扩展新结点
				t[newz] = s[z];
				t[z] = s[newz];
				dist[rear] = dist[front] + 1; //更新新结点的距离值 
				if(try_to_insert(rear))
					rear++;
			} 
		}		 
		front++; //扩展完毕再修改对首指针 
//		cout << front << " ";
	}
	return 0;    //失败	 
}

int main(){
	for(int i = 0; i < 9; i++)
		cin >> st[1][i];
	for(int i = 0; i < 9; i++)
		cin >> goal[i];
	int ans = bfs();
	if(ans > 0)
		cout << dist[ans] ;
	else
		cout << -1;
		
	return 0;
} 
原文地址:https://www.cnblogs.com/zhumengdexiaobai/p/7748045.html