八数码问题

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

第一次做用的暴力做法,用一个变量保存状态,用$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 }
posted @ 2019-11-28 21:26  dzcixy  阅读(411)  评论(0)    收藏  举报