八数码问题
一:八数码输出最短路径长度:

第一次做用的暴力做法,用一个变量保存状态,用$bfs$去扩展。但是这样会超时,暴力的话没有优化过不去。最后将$map$改成$unordered\_map$过了。ps:用逆序对判错能快一倍。代码:
1 #include <iostream> 2 #include <string> 3 #include <unordered_map> 4 #include <queue> 5 6 using namespace std; 7 8 int dx[4] = {0, 0, 1, -1}; 9 int dy[4] = {1, -1, 0, 0}; 10 11 int bfs(string start) 12 { 13 int dx[4] = {-1, 0, 1, 0}; 14 int dy[4] = {0, 1, 0, -1}; 15 string end = "12345678x"; 16 unordered_map<string, int> dis; 17 queue<string> q; 18 19 q.push(start); 20 dis[start] = 0; 21 22 while(q.size()) 23 { 24 string t = q.front(); 25 q.pop(); 26 27 28 string state = t; 29 if(state == end)return dis[state];//第一次找到答案,就是最短路 30 31 int x, y; 32 for(int i = 0 ; i < state.size() ; i ++)//找出x的位置,也可以用string的find函数 33 if(state[i] == 'x') 34 { 35 x = i / 3, y = i % 3; 36 break; 37 } 38 39 string source = state; 40 for(int i = 0 ; i < 4 ; i ++) 41 { 42 int a = x + dx[i], b = y + dy[i]; 43 if (a >= 0 && a < 3 && b >= 0 && b < 3)//保证不出界 44 { 45 swap(state[x * 3 + y], state[a * 3 + b]); 46 if (!dis.count(state))//如果没有这个状态就扩展 47 { 48 dis[state] = dis[source] + 1; 49 q.push(state); 50 } 51 swap(state[x * 3 + y], state[a * 3 + b]); 52 } 53 } 54 } 55 return -1; 56 } 57 58 59 int main(){ 60 string start; 61 for(int i = 0 ; i < 9 ; i ++){ 62 char c; 63 cin >> c; 64 start += c; 65 } 66 67 cout << bfs(start) << endl; 68 return 0; 69 }
因为八数码有玄学(其实是不会证明)判断是不是有答案,逆序对的数量是奇数的话就无解。改用了$A*$算法,用每个数字和它所处位置的曼哈顿距离的和作为估价函数。效果奇佳,速度快了十几倍。代码:
1 #include <iostream> 2 #include <algorithm> 3 #include <queue> 4 #include <map> 5 #include <string> 6 7 #define x first 8 #define y second 9 10 using namespace std; 11 12 13 typedef pair<int, string> PIS; 14 15 int f(string state) 16 { 17 int res = 0; 18 for(int i = 0 ; i < state.size() ; i ++) 19 if(state[i] != 'x') 20 { 21 int t = state[i] - '1'; 22 res += abs(i / 3 - t / 3) + abs(i % 3 - t % 3); 23 } 24 return res; 25 } 26 27 int bfs(string start) 28 { 29 int dx[4] = {-1, 0, 1, 0}; 30 int dy[4] = {0, 1, 0, -1}; 31 string end = "12345678x"; 32 map<string, int> dis; 33 priority_queue<PIS, vector<PIS>, greater<PIS>> heap; 34 35 heap.push({f(start), start}); 36 dis[start] = 0; 37 38 while(heap.size()) 39 { 40 auto t = heap.top(); 41 heap.pop(); 42 43 string state = t.y; 44 if(state == end)return dis[state]; 45 46 int x, y; 47 for(int i = 0 ; i < state.size() ; i ++) 48 if(state[i] == 'x') 49 { 50 x = i / 3, y = i % 3; 51 break; 52 } 53 54 string source = state; 55 for(int i = 0 ; i < 4 ; i ++) 56 { 57 int a = x + dx[i], b = y + dy[i]; 58 if (a >= 0 && a < 3 && b >= 0 && b < 3) 59 { 60 swap(state[x * 3 + y], state[a * 3 + b]); 61 if (!dis.count(state) || dis[state] > dis[source] + 1) 62 { 63 dis[state] = dis[source] + 1; 64 heap.push({dis[state] + f(state), state}); 65 } 66 swap(state[x * 3 + y], state[a * 3 + b]); 67 } 68 } 69 } 70 71 return -1; 72 } 73 74 75 int main(){ 76 string start, seq, c; 77 while(cin >> c) 78 { 79 start += c; 80 if(c != "x")seq += c; 81 } 82 83 int res = 0; 84 //找出逆序对的数量 85 for(int i = 0 ; i < seq.size() ; i ++) 86 for(int j = 0 ; j < i ; j ++) 87 if(seq[j] > seq[i]) 88 res ++; 89 if(res & 1)puts("-1");//是奇数就无答案 90 else cout << bfs(start) << endl; 91 92 return 0; 93 }
二:八数码输出最短路径

只要在前面的基础上,用一个$map$记录每一个状态是从哪一个状态转移过来的,最后从最后一个状态倒推回去,再逆序即可。(因为路径不唯一,题目也没要求输出字典序最小等要求),代码:
1 #include <iostream> 2 #include <algorithm> 3 #include <queue> 4 #include <map> 5 #include <string> 6 7 #define x first 8 #define y second 9 10 using namespace std; 11 12 13 typedef pair<int, string> PIS; 14 15 int f(string state) 16 { 17 int res = 0; 18 for(int i = 0 ; i < state.size() ; i ++) 19 if(state[i] != 'x') 20 { 21 int t = state[i] - '1'; 22 res += abs(i / 3 - t / 3) + abs(i % 3 - t % 3); 23 } 24 return res; 25 } 26 27 string bfs(string start) 28 { 29 int dx[4] = {-1, 0, 1, 0}; 30 int dy[4] = {0, 1, 0, -1}; 31 char op[] = "urdl"; 32 string end = "12345678x"; 33 map<string, int> dis; 34 map<string, pair<string, char>> prev; 35 priority_queue<PIS, vector<PIS>, greater<PIS>> heap; 36 37 heap.push({f(start), start}); 38 dis[start] = 0; 39 40 while(heap.size()) 41 { 42 auto t = heap.top(); 43 heap.pop(); 44 45 string state = t.y; 46 if(state == end)break; 47 48 int x, y; 49 for(int i = 0 ; i < state.size() ; i ++) 50 if(state[i] == 'x') 51 { 52 x = i / 3, y = i % 3; 53 break; 54 } 55 56 string source = state; 57 for(int i = 0 ; i < 4 ; i ++) 58 { 59 int a = x + dx[i], b = y + dy[i]; 60 if (a >= 0 && a < 3 && b >= 0 && b < 3) 61 { 62 swap(state[x * 3 + y], state[a * 3 + b]); 63 if (!dis.count(state) || dis[state] > dis[source] + 1) 64 { 65 dis[state] = dis[source] + 1; 66 prev[state] = {source, op[i]};//记录转移 67 heap.push({dis[state] + f(state), state}); 68 } 69 swap(state[x * 3 + y], state[a * 3 + b]); 70 } 71 } 72 } 73 string ans; 74 while(end != start)//回溯 75 { 76 ans += prev[end].y; 77 end = prev[end].x; 78 } 79 reverse(ans.begin(), ans.end()); 80 return ans; 81 } 82 83 84 int main(){ 85 string start, seq, c; 86 while(cin >> c) 87 { 88 start += c; 89 if(c != "x")seq += c; 90 } 91 92 int res = 0; 93 for(int i = 0 ; i < seq.size() ; i ++) 94 for(int j = 0 ; j < i ; j ++) 95 if(seq[j] > seq[i]) 96 res ++; 97 if(res & 1)puts("unsolvable"); 98 else cout << bfs(start) << endl; 99 100 return 0; 101 }

浙公网安备 33010602011771号