POJ~1077~八數碼~IDA*解題報告

八數碼:

題目描述:

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");
	}
	
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章