The title is described as follows:
The goal of the 15 puzzle problem is to complete pieces on
4×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×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
Main idea:
There is a 4 * 4 square grid, in which 0-15 numbers can be placed, and only 0 can be moved at a time. The order of 1-15 can be obtained by finding the minimum steps.
Because the time and space complexity of ordinary bfs is large, heuristic search is used to reduce the complexity.
IDEA *: find the shortest by limiting the depth of dfs
A *: search by greedily selecting the local shortest every time through the estimation function and the priority queue
IDAE*:
#include<bits/stdc++.h> #define N 4 #define N2 16 #define LIMIT 100 using namespace std; const int dx[4] = {0,-1,0,1}; const int dy[4] = {1,0,-1,0}; const char dir[4] = {'r','u','l','d'}; int MDT[N2][N2]; struct Puzzle{ int f[N2],space,MD; }; Puzzle state; int limit; int path[LIMIT]; int getAllMd(Puzzle pz) { int sum = 0; for(int i = 0;i < N2;i++) { if(pz.f[i] == N2) continue;//Spaces are not included in Manhattan distance sum += MDT[i][pz.f[i] - 1]; } return sum; } bool IsSolved() { for(int i = 0;i < N2;i++) if(state.f[i] != i+1) return false; return true; } bool dfs(int depth,int pre) { if(state.MD == 0) return true; if(depth + state.MD > limit) return false; int sx = state.space / N; int sy = state.space % N; Puzzle temp; for(int r = 0;r < 4;r++) { int tx = sx + dx[r]; int ty = sy + dy[r]; if(tx < 0 || ty < 0 || tx >= N || ty >= N) continue; if(abs(pre - r) == 2) continue;//Back to the previous step temp = state; state.MD -= MDT[tx * N + ty][state.f[tx * N + ty] - 1];//Subtract the Manhattan distance of tx*N+ty state.MD += MDT[sx * N + sy][state.f[tx * N + ty] - 1];//Recalculation plus swap(state.f[tx * N + ty],state.f[sx * N + sy]); state.space = tx * N + ty; if(dfs(depth+1,r)) {path[depth] = r;return true;} state = temp; } return false ; } string iterative_deepening(Puzzle in) { in.MD = getAllMd(in); for(limit = in.MD;limit <= LIMIT;limit++) { state = in; if(dfs(0,-100)) { string ans = ""; for(int i = 0;i < limit;i++) ans += dir[path[i]]; return ans; } } return "unsolvable"; } int main() { for(int i = 0;i < N2;i++) for(int j = 0;j < N2;j++) MDT[i][j] = abs(i/N - j/N) + abs(i%N - j%N); Puzzle in; for(int i = 0;i < N2;i++) { cin>>in.f[i]; if(in.f[i] == 0) { in.f[i] = N2; in.space = i; } } string ans = iterative_deepening(in); cout<<ans<<endl; cout<<ans.size()<<endl; return 0; }
A*:
#include<bits/stdc++.h> #define N 4 #define N2 16 using namespace std; const int dx[4] = {0,-1,0,1}; const int dy[4] = {1,0,-1,0}; const char dir[4] = {'r','u','l','d'}; int MDT[N2][N2]; struct Puzzle { int f[N2],space,MD; int cost; bool operator < (const Puzzle &p)const { for(int i = 0;i < N2;i++) { if(f[i] == p.f[i]) continue; return f[i] < p.f[i]; } return false; } }; struct State{ Puzzle puzzle; int estimated; bool operator < (const State &s) const { return estimated > s.estimated; } }; int getAllMd(Puzzle pz) { int sum = 0; for(int i = 0;i < N2;i++) { if(pz.f[i] == N2) continue; sum += MDT[i][pz.f[i] - 1]; } return sum; } int astar(Puzzle s) { priority_queue<State> PQ; s.MD = getAllMd(s); s.cost = 0; map<Puzzle,bool> V; Puzzle u,v; State init; init.puzzle = s; init.estimated = getAllMd(s); PQ.push(init); while(!PQ.empty()) { State st = PQ.top();PQ.pop(); u = st.puzzle; if(u.MD == 0) return u.cost; V[u] = true; int sx = u.space / N; int sy = u.space % N; for(int r = 0;r < 4;r++) { int tx = sx + dx[r]; int ty = sy + dy[r]; if(tx < 0 || ty < 0 || tx >= N || ty >= N) continue; v = u; v.MD -= MDT[tx * N + ty][v.f[tx * N + ty] - 1]; v.MD += MDT[sx * N + sy][v.f[tx * N + ty] - 1]; swap(v.f[sx * N + sy],v.f[tx * N + ty]); v.space = tx * N + ty; if(!V[v]) { v.cost++; State now; now.puzzle = v; now.estimated = v.cost + v.MD; PQ.push(now); } } } return -1; } int main() { for(int i = 0;i < N2;i++) { for(int j = 0;j < N2;j++) { MDT[i][j] = abs(i/N - j/N) + abs(i%N - j%N); } } Puzzle in; for(int i = 0;i < N2;i++) { cin>>in.f[i]; if(in.f[i] == 0) { in.f[i] = N2; in.space = i; } } cout<<astar(in)<<endl; return 0; }