【转】别人家的八数码 A* IDA*解法

【转】 http://www.cnblogs.com/liyongmou/archive/2010/07/19/1780861.html

 

  1 代码
  2 
  3 // A*
  4 #include
  5 #include
  6 #include
  7 #include
  8 #include
  9 using namespace std;
 10 
 11 /* 把1..n的排列映射为数字 0..(n!-1) */
 12 int fac[] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 };//...
 13 int order(const char *s, int n) {
 14     int i, j, temp, num;
 15 
 16     num = 0;
 17 
 18     for (i = 0; i < n-1; i++) {
 19         temp = 0;
 20         for (j = i + 1; j < n; j++) {
 21             if (s[j] < s[i])
 22                 temp++;
 23         }
 24         num += fac[s[i] -1] * temp;
 25     }
 26     return num;
 27 }
 28 
 29 bool is_equal(const char *b1, const char *b2){
 30     for(int i=0; i<9; i++)
 31         if(b1[i] != b2[i])
 32             return false;
 33     return true;
 34 }
 35 
 36 
 37 //hash
 38 struct node{
 39     char board[9];
 40     char space;//空格所在位置
 41 };
 42 
 43 const int TABLE_SIZE = 362880;
 44 
 45 int hash(const char *cur){
 46     return order(cur, 9);
 47 }
 48 
 49 /* 整数映射成排列 */
 50 void get_node(int num, node &tmp) {
 51     int n=9;
 52     int a[9]; //求逆序数
 53     for (int i = 2; i <= n; ++i) {
 54         a[i - 1] = num % i;
 55         num = num / i;
 56         tmp.board[i - 1] = 0;//初始化
 57     }
 58     tmp.board[0] = 0;
 59     int rn, i;
 60     for (int k = n; k >= 2; k--) {
 61         rn = 0;
 62         for (i = n - 1; i >= 0; --i) {
 63             if (tmp.board[i] != 0)
 64                 continue;
 65             if (rn == a[k - 1])
 66                 break;
 67             ++rn;
 68         }
 69         tmp.board[i] = k;
 70     }
 71     for (i = 0; i < n; ++i)
 72         if (tmp.board[i] == 0) {
 73             tmp.board[i] = 1;
 74             break;
 75         }
 76     tmp.space = n - a[n-1] -1;
 77 }
 78 
 79 //启发函数: 除去x之外到目标的网格距离和
 80 int goal_state[9][2] = {{0,0}, {0,1}, {0,2},
 81         {1,0}, {1,1}, {1,2}, {2,0}, {2,1}, {2,2}};
 82 int h(const char *board){
 83     int k;
 84     int hv = 0;
 85     for(int i=0; i<3; ++i)
 86         for(int j=0; j<3; ++j){
 87             k = i*3+j;
 88             if(board[k] != 9){
 89                 hv += abs(i - goal_state[board[k]-1][0]) +
 90                         abs(j - goal_state[board[k] -1][1]);
 91             }
 92         }
 93     return hv;
 94 }
 95 
 96 int f[TABLE_SIZE], d[TABLE_SIZE];//估计函数和深度
 97 
 98 //优先队列的比较对象
 99 struct cmp{
100     bool operator () (int u, int v){
101         return f[u] > f[v];
102     }
103 };
104 char color[TABLE_SIZE];//0, 未访问;1, 在队列中,2, closed
105 int parent[TABLE_SIZE];
106 char move[TABLE_SIZE];
107 int step[4][2] = {{-1, 0},{1, 0}, {0, -1}, {0, 1}};//u, d, l, r
108 
109 void A_star(const node & start){
110     int x, y, k, a, b;
111     int u, v;
112     priority_queue<int, vector<int>, cmp> open;
113     memset(color, 0, sizeof(char) * TABLE_SIZE);
114 
115     u = hash(start.board);
116     parent[u] = -1;
117     d[u] = 0;
118     f[u] = h(start.board);
119     open.push(u);
120     color[u] = 1;
121 
122     node tmp, cur;
123     while(!open.empty()){
124         u = open.top();
125         if(u == 0)
126             return;
127         open.pop();
128 
129         get_node(u, cur);
130 
131         k = cur.space;
132         x = k / 3;
133         y = k % 3;
134         for(int i=0; i<4; ++i){
135             a = x + step[i][0];
136             b = y + step[i][1];
137             if(0<=a && a<=2 && 0<=b && b<=2){
138                 tmp = cur;
139                 tmp.space = a*3 + b;
140                 swap(tmp.board[k], tmp.board[tmp.space]);
141                 v = hash(tmp.board);
142                 if(color[v] == 1 && (d[u] + 1) < d[v]){//v in open
143                     move[v] = i;
144                     f[v] = f[v] - d[v] + d[u] + 1;//h[v]已经求过
145                     d[v] = d[u] + 1;
146                     parent[v] = u;
147                     //直接插入新值, 有冗余,但不会错
148                     open.push(v);
149                 }
150                 else if(color[v] == 2 && (d[u]+1)//v in closed
151                     move[v] = i;
152                     f[v] = f[v] - d[v] + d[u] + 1;//h[v]已经求过
153                     d[v] = d[u] + 1;
154                     parent[v] = u;
155                     open.push(v);
156                     color[v] = 1;
157                 }
158                 else if(color[v] == 0){
159                     move[v] = i;
160                     d[v] = d[u] + 1;
161                     f[v] = d[v] + h(tmp.board);
162                     parent[v] = u;
163                     open.push(v);
164                     color[v] = 1;
165                 }
166             }
167         }
168         color[u] = 2; //
169     }
170 }
171 
172 void print_path(){
173     int n, u;
174     char path[1000];
175     n = 1;
176     path[0] = move[0];
177     u = parent[0];
178     while(parent[u] != -1){
179         path[n] = move[u];
180         ++n;
181         u = parent[u];
182     }
183     for(int i=n-1; i>=0; --i){
184         if(path[i] == 0)
185             printf("u");
186         else if(path[i] == 1)
187             printf("d");
188         else if(path[i] == 2)
189             printf("l");
190         else
191             printf("r");
192     }
193 }
194 
195 int main(){
196     //freopen("in", "r", stdin);
197 
198     node start;
199     char c;
200     for(int i=0; i<9; ++i){
201         cin>>c;
202         if(c == 'x'){
203             start.board[i] = 9;
204             start.space = i;
205         }
206         else
207             start.board[i] = c - '0';
208     }
209     A_star(start);
210 
211     if(color[0] != 0)
212         print_path();
213     else
214         printf("unsolvable");
215     return 0;
216 }
A*
 1 代码
 2 
 3 // IDA*
 4 #include
 5 #include
 6 #include
 7 using namespace std;
 8 
 9 #define    SIZE 3
10 
11 char board[SIZE][SIZE];
12 
13 //启发函数: 除去x之外到目标的网格距离和
14 int goal_state[9][2] = {{0,0}, {0,1}, {0,2},
15         {1,0}, {1,1}, {1,2}, {2,0}, {2,1}, {2,2}};
16 int h(char board[][SIZE]){
17     int cost = 0;
18     for(int i=0; ii)
19         for(int j=0; jj){
20             if(board[i][j] != SIZE*SIZE){
21                 cost += abs(i - goal_state[board[i][j]-1][0]) +
22                         abs(j - goal_state[board[i][j]-1][1]);
23             }
24         }
25     return cost;
26 }
27 
28 int step[4][2] = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}};//u, l, r, d
29 char op[4] = {'u', 'l', 'r', 'd'};
30 
31 char solution[1000];
32 int bound;     //上界
33 bool ans;    //是否找到答案
34 int DFS(int x, int y, int dv, char pre_move){// 返回next_bound
35     int hv = h(board);
36     if(hv + dv > bound)
37         return dv + hv;
38     if(hv == 0){
39         ans = true;
40         return dv;
41     }
42 
43     int next_bound = 1e9;
44     for(int i=0; i<4; ++i){
45         if(i + pre_move == 3)//与上一步相反的移动
46             continue;
47         int nx = x + step[i][0];
48         int ny = y + step[i][1];
49         if(0<=nx && nx0<=ny && ny<SIZE){
50             solution[dv] = i;
51             swap(board[x][y], board[nx][ny]);
52 
53             int new_bound = DFS(nx, ny, dv+1, i);
54             if(ans)
55                 return new_bound;
56             next_bound = min(next_bound, new_bound);
57 
58             swap(board[x][y], board[nx][ny]);
59         }
60     }
61     return next_bound;
62 }
63 
64 void IDA_star(int sx, int sy){
65     ans = false;
66     bound = h(board);//初始代价
67     while(!ans && bound <= 100)//上限
68         bound = DFS(sx, sy, 0, -10);
69 }
70 
71 int main(){
72     freopen("in", "r", stdin);
73 
74     int sx, sy;//起始位置
75     char c;
76     for(int i=0; ii)
77         for(int j=0; jj){
78             cin>>c;
79             if(c == 'x'){
80                 board[i][j] = SIZE * SIZE;
81                 sx = i;
82                 sy = j;
83             }
84             else
85                 board[i][j] = c - '0';
86         }
87 
88     IDA_star(sx, sy);
89 
90     if(ans){
91         for(int i=0; ii)
92             cout<<op[solution[i]];
93     }
94     else
95         cout<<"unsolvable";
96 
97     return 0;
98 }
IDA*

 

你可能感兴趣的:(【转】别人家的八数码 A* IDA*解法)