八数码:
题目描述:
The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let's call the missing tile 'x'; the object of the puzzle is to arrange the tiles so that they are ordered as:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 x
where the only legal operation is to exchange 'x' with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:
1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8
9 x 10 12 9 10 x 12 9 10 11 12 9 10 11 12
13 14 11 15 13 14 11 15 13 14 x 15 13 14 15 x
r-> d-> r->
The letters in the previous row indicate which neighbor of the 'x' tile is swapped with the 'x' tile at each step; legal values are 'r','l','u' and 'd', for right, left, up, and down, respectively.
Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and
frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing 'x' tile, of course).
In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three
arrangement.
Input:
You will receive a description of a configuration of the 8 puzzle. The description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus ‘x’. For example, this puzzle
1 2 3
x 4 6
7 5 8
is described by this list:
1 2 3 x 4 6 7 5 8
Output:
You will print to standard output either the word ``unsolvable’’, if the puzzle has no solution, or a string consisting entirely of the letters ‘r’, ‘l’, ‘u’ and ‘d’ that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line.。
Sample Input:
2 3 4 1 5 x 7 6 8
Sample Output:
ullddrurdllurdruldr
题目大意:
其实这道题很简单理解,就是简单的九宫格排序问题,而只能移动上下左右这四个方向,并且还要满足1 2 3 4 5 6 7 8 x这样的排序即可.
思路分析:
IDA算法是A算法和迭代加深算法的结合。它既有A*的估值函数判断,以及迭代操作避免不必要的搜索。那么题目中我们需要找出一个预定义的最大搜索深度,以此来限制搜索的进行,这里题目给出了九位数字(将x当做9),最坏的情况是在每个位置搜索9次,那么就有81次搜索深度,那么可以四舍五入为100,防止搜索深度不够,在搜索的时候,通过当前局面的估价函数值+当前的搜索深度 > 预定义的最大搜索深度时,就进行剪枝。这里的估值函数运用了曼哈顿距离来判断,下面会给出原理介绍,接下来在搜索所进行的操作请看代码详解:
曼哈顿距离:这里因为是九宫格,所以可以用2点坐标的绝对值差
来表示所需要的代价,|x1-x2|+|y1-y2|这里即为上述所讲的h,
将所有h相加即为H。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
using namespace std;
typedef struct node
{
int s[9];//记录元素
int loc;//x的位置
}Lemon;
int di[5][2]={{1,0},{-1,0},{0,1},{0,-1}};//方向变量
char di1[5]={"durl"};//方向符号
int dish(int s1[])//曼哈顿距离
{
int num=0;
for(int i=0;i<9;i++)
{
if(s1[i]!=9)
{
int x=i/3;
int y=i%3;
int x1=(s1[i]-1)/3;
int y1=(s1[i]-1)%3;
num+=abs(x-x1)+abs(y-y1);
}
}
return num;
}
char c2[1000];
int LemonsIDA(int limit,int depth,int pre,Lemon now)//limit为限制,depth为深度
//pre是记录上次方向(i),防止重复
{
if(dish(now.s)==0)//如果曼哈顿距离为0,说明已经达到123456789
{
c2[depth]='\0';
puts(c2);
return 1;
}
int x=now.loc/3;
int y=now.loc%3;
//得到位置
for(int i=0;i<4;i++)//操作方向
{
if(i+pre==1 || i+pre==5)continue;//这一步是为了剪枝,防止走了一步又退一步
int x1=x+di[i][0];
int y1=y+di[i][1];
if(x1<0 || y1<0 || x1>2 || y1>2)continue;//边界判断
else
{
Lemon tp=now;
tp.loc=x1*3+y1;
tp.s[now.loc]=tp.s[tp.loc];
tp.s[tp.loc]=9;
//移动2个模块的数字
c2[depth]=di1[i];//记录方向符号
if(depth+1+dish(tp.s)<=limit)//判断是否超过限制,通过深度与曼哈顿
{
if(LemonsIDA(limit,depth+1,i,tp)==1)//回溯判断
{
return 1;
}
}
}
}
return 0;
}
int main()
{
Lemon now;
char c1;
for(int i=0;i<9;i++)
{
cin >> c1;
if(c1=='x')
{
now.s[i]=9;
now.loc=i;
}
else
{
now.s[i]=c1-'0';
}
}
int limit;
for(limit=0;limit<=100;limit++)//这里做一下,因为要移动9个数字,最坏的情况为9!
//那么每次判断所要移动的次数作为限制,以此来达成递归的边界。
{
if(LemonsIDA(limit,0,2e9,now)==1)
{
break;
}
}
if(limit > 100)//如果大于100,说明该数字,无法组成完整的顺序九宫格
{
puts("unsolvable");
}
}