Eight
Time Limit: 10000/5000 MS (java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 22196 Accepted Submission(s): 5961 Special Judge
PRoblem Description 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, several descriptions of configuration of the 8 puzzle. One 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. Do not print a blank line between cases.
Sample Input 2 3 4 1 5 x 7 6 8
Sample Output ullddrurdllurdruldr
第一个A*搜索,A*是一种启发式搜索,g为已花代价,h为估计的剩余代价,而A*是根据f=g+h作为估价函数进行排列,也就是优先选择可能最优的节点进行扩展。
对于八数码问题,以下几个问题需要知道 判断有无解问题:根据逆序数直接判断有无解,对于一个八数码,依次排列之后,每次是将空位和相邻位进行调换,研究后会发现,每次调换,逆序数增幅都为偶数,也就是不改变奇偶性,所以只需要根据初始和目标状态的逆序数正负判断即可。
Hash问题:根据的是康托展开,点击查看康托展开介绍 估价函数: 是根据与目标解的曼哈顿距离,也就是每个数字与目标位置的曼哈顿距离之和。
代码:
#include <iostream>#include <string>#include <cstring>#include <cstdio>#include <cmath>#include <cstdlib>#include <algorithm>#include <queue>#include <map>#define MST(s,q) memset(s,q,sizeof(s))#define INF 0x3f3f3f3f#define MAXN 9999using namespace std;struct node{ int Map[3][3]; int h, g; int x, y; // 空位的位置 int hash;//Hash值 bool operator<(const node a)const { if (h == a.h) return g > a.g; return h > a.h; // 717ms //return h + g > a.h + a.g; // 1326ms } bool check() // 判断空位位置是否合法 { if (x >= 0 && x <= 2 && y >= 0 && y <= 2) return 1; return 0; }} s, u, v;int Hash[9] = {40320, 5040, 720, 120, 24, 6, 2, 1, 1};int Final = 46233; //46233 //1 2 3 4 5 6 7 8 0的康托展开int pre[400000];//记录路径int vis[400000];// 判断是否已经遍历,int move_x[4] = { -1, 1, 0, 0}, move_y[4] = {0, 0, -1, 1}; // 移动方向顺序不同,输出答案不一样,但都ac了bool isok(node s) // 根据给定的初始状态的逆序数判断能否解决问题{ int a[10], k = 1; for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) a[k++] = s.Map[i][j]; int sum = 0; for (int i = 1; i <= 9; i++) for (int j = i + 1; j <= 9; j++) if (a[j] && a[i] && a[j] < a[i]) sum++; if (sum % 2 == 0) return 1; return 0;}int get_h(node s){ int ans = 0; for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) if (s.Map[i][j]) ans += abs(i - (s.Map[i][j] - 1) / 3) + abs(j - (s.Map[i][j] - 1) % 3); //注意s.Map[i][j]要-1 return ans;}int getHash(node s){ int a[10], k = 1; for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) a[k++] = s.Map[i][j]; int ans = 0; for (int i = 1; i <= 9; i++) { k = 0; for (int j = i + 1; j <= 9; j++) if (a[j] < a[i]) k++; ans += Hash[i - 1] * k; } return ans;}void Astar(){ priority_queue<node> Q; Q.push(s); while (!Q.empty()) { u = Q.top(); Q.pop(); for (int i = 0; i < 4; i++) { v = u; v.x += move_x[i], v.y += move_y[i]; if (v.check()) { swap(v.Map[v.x][v.y], v.Map[u.x][u.y]); v.hash = getHash(v); if (vis[v.hash] == -1) { vis[v.hash] = i; v.g++; v.h = get_h(v); pre[v.hash] = u.hash; Q.push(v); } if (v.hash == Final) { return; } } } }}void printRoad(){ string ans; int k = Final; while (pre[k] != -1) { switch (vis[k]) { case 0: ans += 'u'; break; case 1: ans += 'd'; break; case 2: ans += 'l'; break; case 3: ans += 'r'; break; } k = pre[k]; } for (int i = ans.size() - 1; i >= 0; i--) putchar(ans[i]); printf("/n");}int main(){ string tmp; while (getline(cin, tmp)) { int k = 0; memset(vis, -1, sizeof(vis)); memset(pre, -1, sizeof(pre)); for (int i = 0; i < tmp.size(); i++) { if (tmp[i] == 'x') s.Map[k / 3][k % 3] = 0, s.x = k / 3, s.y = k % 3, k++; else if (tmp[i] >= '0' && tmp[i] <= '9') s.Map[k / 3][k % 3] = tmp[i] - '0', k++; } if (!isok(s)) { printf("unsolvable/n"); continue; } s.hash = getHash(s); if (s.hash == Final) { printf("/n"); continue; } vis[s.hash] = -2; s.g = 0; s.h = get_h(s); Astar(); printRoad(); }}新闻热点
疑难解答