【转】别人家的八数码 A* IDA*解法
【转】 http://www.cnblogs.com/liyongmou/archive/2010/07/19/1780861.html
1 代码 2 3 // A* 4 #include<iostream> 5 #include<cstdio> 6 #include<cstring> 7 #include<cstdlib> 8 #include<queue> 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)<d[v]){//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 }
1 代码 2 3 // IDA* 4 #include<iostream> 5 #include<cstdio> 6 #include<cstdlib> 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; i<SIZE; ++i) 19 for(int j=0; j<SIZE; ++j){ 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 && nx<SIZE && 0<=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; i<SIZE; ++i) 77 for(int j=0; j<SIZE; ++j){ 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; i<bound; ++i) 92 cout<<op[solution[i]]; 93 } 94 else 95 cout<<"unsolvable"; 96 97 return 0; 98 }