题目:
简单介绍一下八数码问题:
在一个3×3的九宫格上,填有1~8八个数字,空余一个位置,例如下图:
1 | 2 | 3 |
4 | 5 | 6 |
7 | 8 |
在上图中,由于右下角位置是空的,你可以移动数字,比如可以将数字6下移一位:
1 | 2 | 3 | 1 | 2 | 3 | |
4 | 5 | 6 | → | 4 | 5 | |
7 | 8 | 7 | 8 | 6 |
或者将数字8右移一位:
1 | 2 | 3 | 1 | 2 | 3 | |
4 | 5 | 6 | → | 4 | 5 | 6 |
7 | 8 | 7 | 8 |
1~8按顺序排列的情况称为“初始状态”(如最上方图)。“八数码问题”即是求解对于任意的布局,将其移动至“初始状态”的方法。
给定一个现有的九宫格布局,请输出将它移动至初始状态的移动方法的步骤。
输入:
输入包含多组数据,处理至文件结束。每组数据占一行,包含8个数字和表示空位的‘x’,各项以空格分隔,表示给定的九宫格布局。
例如,对于九宫格
1 | 2 | 3 |
4 | 6 | |
7 | 5 | 8 |
输入应为:1 2 3 x 4 6 7 5 8
输出:
对于每组输入数据,输出一行,即移动的步骤。向上、下、左、右移动分别用字母u、d、l、r表示;如果给定的布局无法移动至“初始 状态”,请输出unsolvable。
如果有效的移动步骤有多种,输出任意即可。
样例:
分析:双向BFS,简单来说就是同时进行两个BFS,但每个BFS的vis数组有了新的用途即判断另一个BFS是否达到此BFS扩展到的此刻的点,若抵达即连通。
unsolvable的情况用逆序数的奇偶性判断,因为目标状态12345678逆序数为0,所以当前态的逆序数必为偶
用康托展开记录字典序用于状态压缩(hash)
1 #include<iostream> 2 #include<sstream> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<string> 6 #include<cstring> 7 #include<algorithm> 8 #include<functional> 9 #include<iomanip> 10 #include<numeric> 11 #include<cmath> 12 #include<queue> 13 #include<vector> 14 #include<set> 15 #include<cctype> 16 #define PI acos(-1.0) 17 const int INF = 0x3f3f3f3f; 18 const int NINF = -INF - 1; 19 typedef long long ll; 20 using namespace std; 21 int fac[10] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880}; 22 int vis1[362885], vis2[362885]; 23 int eda[9]={ 1, 2, 3, 4, 5, 6, 7, 8, 0}; 24 string path[362885]; 25 int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, -1, 1}; 26 char p1[4] = {'d', 'u', 'l', 'r'}, p2[4] = {'u', 'd', 'r', 'l'}; 27 struct node 28 { 29 int s[9]; 30 int cur, n;//cur目前x所在位置,n为hash值 31 }st; 32 int cantor(int *s)//康托展开 33 { 34 int sum = 1; 35 for (int i = 0;i < 9; ++i) 36 { 37 int k = 0; 38 for (int j = i + 1; j < 9; ++j) 39 if( s[j] < s[i]) k++; 40 sum += k * fac[8 - i]; 41 } 42 return sum; 43 } 44 void bfs() 45 { 46 memset(vis1, 0, sizeof(vis1)); 47 memset(vis2, 0, sizeof(vis2)); 48 queue<node> q1, q2; 49 st.n = cantor(st.s); 50 q1.push(st); 51 vis1[st.n] = 1; 52 path[st.n] = "";//重要 53 node ed; 54 memcpy(ed.s, eda, sizeof(ed.s)); 55 ed.n = cantor(ed.s); 56 ed.cur = 8; 57 path[ed.n] = ""; 58 q2.push(ed); 59 vis2[ed.n] = 1; 60 while (q1.size() || q2.size()) 61 { 62 node temp1 = q1.front(); 63 q1.pop(); 64 int x1 = temp1.cur / 3, y1 = temp1.cur % 3; 65 for (int i = 0; i < 4; ++i) 66 { 67 int nx = x1 + dx[i], ny = y1 + dy[i]; 68 if (nx < 0 || nx > 2 || ny < 0 || ny > 2) continue; 69 node rec = temp1; 70 rec.cur = nx * 3 + ny; 71 swap(rec.s[temp1.cur], rec.s[rec.cur]); 72 rec.n = cantor(rec.s); 73 if (vis2[rec.n]) 74 { 75 reverse(path[rec.n].begin(), path[rec.n].end()); 76 cout << path[temp1.n] << p1[i] << path[rec.n] << endl; 77 return; 78 } 79 if (!vis1[rec.n]) 80 { 81 vis1[rec.n] = 1; 82 path[rec.n] = path[temp1.n]; 83 path[rec.n] += p1[i]; 84 q1.push(rec); 85 } 86 } 87 node temp2 = q2.front(); 88 q2.pop(); 89 int x2 = temp2.cur / 3, y2 = temp2.cur % 3; 90 for (int i = 0; i < 4; ++i) 91 { 92 int nx = x2 + dx[i], ny = y2 + dy[i]; 93 if (nx < 0 || nx > 2 || ny < 0 || ny > 2) continue; 94 node rec = temp2; 95 rec.cur = nx * 3 + ny; 96 swap(rec.s[temp2.cur], rec.s[rec.cur]); 97 rec.n = cantor(rec.s); 98 if (vis1[rec.n]) 99 { 100 reverse(path[temp2.n].begin(), path[temp2.n].end()); 101 cout << path[rec.n] << p2[i] << path[temp2.n] << endl; 102 return; 103 } 104 if (!vis2[rec.n]) 105 { 106 vis2[rec.n] = 1; 107 path[rec.n] = path[temp2.n]; 108 path[rec.n] += p2[i]; 109 q2.push(rec); 110 } 111 } 112 } 113 } 114 115 int main() 116 { 117 char c; 118 while(cin >> c) 119 { 120 if(c == 'x') 121 { 122 st.s[0] = 0; 123 st.cur = 0; 124 } 125 else st.s[0] = c - '0'; 126 for (int i = 1; i < 9; ++i) 127 { 128 cin >> c; 129 if ( c == 'x') 130 { 131 st.s[i] = 0; 132 st.cur = i; 133 } 134 else st.s[i] = c - '0'; 135 } 136 int k = 0; 137 for(int i = 0; i < 8; ++i) 138 { 139 if (st.s[i]) 140 { 141 for (int j = i + 1; j < 9; ++j) 142 if (st.s[j] < st.s[i] && st.s[j]) k++; 143 } 144 } 145 if(k & 1) cout<< "unsolvable" << endl; 146 else bfs(); 147 } 148 return 0; 149 }