# Aizu ALDS1_13_C 15 Puzzle（八数码问题升级 十五数码问题 BFS IDA*入门 剪枝）

The goal of the 15 puzzle problem is to complete pieces on 4×44×4 cells where one of the cells is empty space.

In this problem, the space is represented by 0 and pieces are represented by integers from 1 to 15 as shown below.

1 2 3 4
6 7 8 0
5 10 11 12
9 13 14 15


You can move a piece toward the empty space at one step. Your goal is to make the pieces the following configuration in the shortest move (fewest steps).

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 0


Write a program which reads an initial state of the puzzle and prints the fewest steps to solve the puzzle.

## Input

The 4×44×4 integers denoting the pieces or space are given.

## Output

Print the fewest steps in a line.

## Constraints

• The given puzzle is solvable in at most 45 steps.

## Sample Input

1 2 3 4
6 7 8 0
5 10 11 12
9 13 14 15


## Sample Output

8

MLE代码：

#include<stdio.h>
#include<string.h>
#include<map>
#include<queue>
#include<string>
#include<iostream>
using namespace std;

string str;
map<string,int> book;

int nx[4][2]={-1,0,0,1,1,0,0,-1};

struct node
{
string sum;
int step;
};

void bfs()
{
queue<node> q;
node st,en;
st.sum=str;
st.step=0;
q.push(st);
while(!q.empty())
{
st=q.front();
q.pop();

int dis;//找'0'的下标
for(dis=0;dis<16;dis++)
{
if(st.sum[dis]=='0') break;
}
int vx=dis/4;
int vy=dis%4;
for(int i=0;i<4;i++)
{
int tx=vx+nx[i][0];
int ty=vy+nx[i][1];
int tz=tx*4+ty;//交换后的下标
if(tx>=0&&tx<4&&ty>=0&&ty<4)
{
en.sum=st.sum;
en.sum[dis]=st.sum[tz];
en.sum[tz]=st.sum[dis];
if(en.sum=="123456789ABCDEF0")
{
printf("%d\n",st.step+1);
return;
}
if(!book[en.sum])
{
book[en.sum]=1;
en.step=st.step+1;
q.push(en);
}
}
}

}
}

int main()
{
int x;
for(int i=0;i<16;i++)
{
scanf("%d",&x);
if(x>9) str+=x-10+'A';
else str+=x+'0';
}
//cout<<str<<endl;
book.clear();
book[str]=1;
bfs();
return 0;
}

/*
1 2 3 4
5 6 7 8
9 10 11 12
13 14 0 15
*/

IDA*算法就是一种剪枝（在我看来

A*和IDA*算法

IDA*算法解决十五数码问题

A*算法（A-Star）

f^(n)=g^(n)+h^(n)

n是状态的表示，通常是状态的编号之类的。在编程中，可以写作f_hat()或者直接写成f()即可。

g^(n)表示从初始状态到n 总共花费的代价。

h^(n)表示从n到目标状态估计需要花费的代价，对于一个正确的搜索，h^(n)<=h(n)，h(n)表示从n到目标状态的实际代价（没有算出来的时候，当然是求不出来h(n)的，但是可以找到一个h^(n)<=h(n)哦），在这个范围内，h^(n)越接近h(n)，搜索的启发效果越好。

f^(n)的值就是对n这个状态的估价。这个估价主要体现在h^()，因为g^()是已知的；g^()体现了广度优先，当h^()>g^()时，可以省略g^()从而提高效率。

15数码问题是人工智能中的一个经典问题。所谓的15数码问题：就是在一个4*4的16宫格棋盘上，摆放有15个将牌，每一个都刻有1-15中的某一个数码。棋盘中留有一个空格，允许其周围的某一个将牌向空格移动，这样通过移动将牌就可以不断改变将牌的布局。所要求解的问题：是给定一种初始布局(初始状态)和一个目标布局(目标状态),问如何移动数码实现从初始状态到目标状态的转变，下面给出一种示例：

1  2  3  4                          1  2 3  4

5  6  7  8                          5  6 7  8

9  10 1112                         9  10 11 12

13 14 15 0                          0  13 14 15

————————————分割线—————————————
IDA*算法是A*算法和迭代加深算法的结合.
A*算法需要维护open表和close表，以及排序选择最小代价的结点内存空间消耗过多。
IDA*的答题思路是。首先 根据最初的数码表
5 1 2 4
9 6 3 8
13 15 10 11
14 0 7 12

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 0

———————————假装是分割线—————————————

（百度百科：曼哈顿距离

AC代码：

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;

int nx[4][2]={{-1,0},{0,-1},{0,1},{1,0}};//上 左 右 下  置换顺序

//各个数字应在位置对照表
int goal[16][2]= {{3,3},{0,0},{0,1},{0,2},//0 1 2 3
{0,3},{1,0},{1,1},{1,2},//4 5 6 7
{1,3},{2,0},{2,1},{2,2},//8 9 10 11
{2,3},{3,0},{3,1},{3,2}};//12 13 14 15

int map[4][4],map2[16],limit;//limit全部的曼哈顿距离之和
int flag,length;

int hv(int a[][4])//估价函数,曼哈顿距离,小于等于实际总步数
{
int cost=0;
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
int w=map[i][j];
if(w!=0) cost+=abs(i-goal[w][0])+abs(j-goal[w][1]);//不算0
}
}
return cost;
}

void dfs(int x,int y,int len,int pre_move)
{
if(flag) return;
int dv=hv(map);
if(len==limit)
{
if(dv==0)  //成功 退出
{
flag=1;
length=len;
return;
}
else return;  //超过预设长度 回退
}

for(int i=0;i<4;i++)
{
if(i+pre_move==3&&len>0) continue;//不和上一次移动方向相反,对第二步以后而言
int tx=x+nx[i][0];
int ty=y+nx[i][1];
if(tx>=0&&tx<4&&ty>=0&&ty<4)
{
swap(map[x][y],map[tx][ty]);
int p=hv(map);
if(p+len<=limit&&flag==0)
{
dfs(tx,ty,len+1,i);
if(flag) return;
}
swap(map[x][y],map[tx][ty]);
}
}
}

int main()
{
int t=1;
while(t--)
{
int x1,y1;
for(int i=0;i<16;i++)//map一维map2二维
{
scanf("%d",&map2[i]);
if(map2[i]==0)
{
x1=i/4;
y1=i%4;
map[x1][y1]=0;
}
else
{
map[i/4][i%4]=map2[i];
}
}

limit=hv(map);
//printf("limit===%d\n",limit);
flag=0;
length=0;
while(flag==0&&length<=45)//要求45步之内到达
{
dfs(x1,y1,0,0);
if(flag==0) limit++; //得到的是最小步数
}
if(flag) printf("%d\n",length);
}
return 0;
}