八數碼:
題目描述:
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");
}
}