标签:uva 10181 15-puzzle problem 15数码
题目大意:
给你一个八数码的序列,要求你在50步之内还原成,初始的形状,如果可以就输出其路径,否则就输出 This puzzle is not solvable.
解析:
这题是用A*算法实现的,上网查了很多资料,了解了什么是A*算法。
A*算法,实质上是根据估价函数进行bfs,每次都选取估价最小的状态,进行移动。
其中 f(n) 是从初始点经由节点n到目标点的估价函数,
g(n) 是在状态空间中从初始节点到n节点的实际代价,
h(n) 是从n到目标节点最佳路径的估计代价
f(n) = g(n) + h(n)
g(n)在该题中是当前的移动步数,h(n)是当前到状态到终点的曼哈顿距离
还有就是如何判断,15数码是否能满足条件。
设 e 表示空滑块所在的行,n 为在当前滑块之后出现小于当前滑块数值的滑块数目,N 为:
15 15
N = ∑ ni = ∑ ni
i = 1 i = 2
如果 N + e 为偶数,则当前局面有解,否则无解。如以下局面:
13 10 11 6
5 7 4 8
1 12 14 9
3 15 2 0
则有小于 13 并在之后出现滑块的数目为 12,小于 10 并在之后出现的滑块数目为 9,类似的,可以得到
其他滑块的 n 值分别为 9(11),5(6),4(5),4(7),3(4),3(8),0(1),3(12),
3(14),2(9),1(3),1(15),0(2)。所有 n 值的和为 N = 59,空滑块在第 4 行,故 e = 4,则 N + e = 63,为奇数,则以上局面不可解。
该代码被我修改后很快了总共耗时才0.068s
#include <string> #include <queue> #include <map> #include <set> #include <cstring> #include <cstdlib> #include <cstdio> using namespace std; int goal[18][2]; set<string> vis; int dx[] = {0,0,1,-1}; int dy[] = {1,-1,0,0}; struct state { int h , step , x , y ; int board[4][4]; string mov; bool operator < (const state &rhs) const { return h + step > rhs.h + rhs.step; } }; inline int distanc(int x, int y, int xx, int yy) { return abs(x - xx) + abs(y - yy); } int get_h(int b[][4]) { int sum = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (b[i][j] == 0 || (i == goal[b[i][j]][0] && j == goal[b[i][j]][1])) continue; sum += distanc(i, j, goal[b[i][j]][0], goal[b[i][j]][1]); } } return sum*4; } bool isAnswer(int b[][4]){ int sum = 0 , z = 0 , x , y ; int tmp[16]; for (int i = 0; i < 4; i++){ for (int j = 0; j < 4; j++){ tmp[z++] = b[i][j]; if (b[i][j] == 0) x = i, y = j; } } for (int i = 0; i < 16; i++){ for (int j = i + 1; j < 16; j++){ if (tmp[j] < tmp[i] && tmp[j] ) sum++; } } if ((sum + x) % 2 == 0) return false; return true; } bool try_to_insert(int b[][4]) { string st; for(int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) { st.push_back((char)(b[i][j]+'0')); } } if(vis.count(st)) { return false; } return true; } bool Astart(state a) { priority_queue <state> q; vis.clear(); int x, y; state u, v; q.push(a); while (!q.empty()){ u = q.top(); q.pop(); for (int i = 0; i < 4; i++){ x = u.x + dx[i]; y = u.y + dy[i]; if (x >= 0 && y >= 0 && x < 4 && y < 4){ v = u; swap(v.board[x][y], v.board[u.x][u.y]); v.step = u.step + 1; if (v.step > 50) continue; if (i == 0) v.mov.push_back('R'); else if (i == 1) v.mov.push_back('L'); else if (i == 2) v.mov.push_back('D'); else if (i == 3) v.mov.push_back('U'); if (v.mov.size() >= 2) { int back1 = v.mov.size() - 1; int back2 = v.mov.size() - 2; if((v.mov[back1] == 'U' && v.mov[back2] == 'D') ||(v.mov[back1] == 'D' && v.mov[back2] == 'U') ||(v.mov[back1] == 'L' && v.mov[back2] == 'R') ||(v.mov[back1] == 'R' && v.mov[back2] == 'L')) continue; } v.h = get_h(v.board); v.x = x; v.y = y; if (v.h == 0){ printf("%s\n",v.mov.c_str()); return true; } if(try_to_insert(v.board)) { q.push(v); } } } } return false; } int main() { int n = 1, t; memset(goal,0,sizeof(goal)); for (int i = 0; i < 4; i++){ for (int j = 0; j < 4; j++){ goal[n][0] = i; goal[n++][1] = j; } } scanf("%d",&t); while (t--) { state start; for (int i = 0; i < 4; i++){ for (int j = 0; j < 4; j++){ scanf("%d",&start.board[i][j]); if (start.board[i][j] == 0) start.x = i, start.y = j; } } if (!isAnswer(start.board)) { printf("This puzzle is not solvable.\n"); continue; } start.h = 0; start.step = 0; bool final_res = Astart(start); if (!final_res) printf("This puzzle is not solvable.\n"); } return 0; }
UVA - 10181 15-Puzzle Problem(15数码 A*)
标签:uva 10181 15-puzzle problem 15数码
原文地址:http://blog.csdn.net/helloworld10086/article/details/41908903