八数码(A*)
第一道A*,照着A*的框架写的,不是很理解A*,写的也很长,中间有些标记的不太理解,去掉标记在POJ提交通过了,还是没理解A*的思想;
犯了个低级错误:在判断新状态 0 的位置(nx, ny)是否越界时,应该是0 =< nx < 3,结果写成了0<= nx <=3,还叫LJ大牛一块查,最后终于给发现了;
在写 A* 之前以为 A* 会省不少空间(扩展的节点相比 BFS 少很多),实际上却开了两个大数组: f[] 和 g[],一下子感觉也挺浪费的,时间上感觉快了很多,我测试的几组都是0MS,在POJ上提交是64MS;
两周以前就决心花几天时间搞八数码和十五数码(主要是想学学A*),结果一下子就过了十几天,八数码的还是马马虎虎,十五数码目前只能寄希望与IDA*,还想想一下八数码的构造方法(感觉分治的思想可能会用上,虽然分治法行不通)。
1 # include <cstdio> 2 # include <queue> 3 # include <cstring> 4 # include <cmath> 5 /*# include <ctime> */ 6 7 # define N 9 8 9 using namespace std; 10 11 typedef struct state 12 { 13 char a[N]; 14 unsigned short h; 15 unsigned int c; 16 } state; 17 18 typedef struct 19 { 20 int p; 21 char d; 22 }path; 23 24 path p[362885]; 25 26 const char md[] = {'u', 'd', 'l', 'r'}; 27 const short int dir[][2] = {{-1,0}, {1,0}, {0,-1}, {0,1}}; 28 const int fact[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320}; 29 30 unsigned short int g[362885]; 31 unsigned short int f[362885]; 32 33 struct cmp{ 34 bool operator()(state s1, state s2){ 35 return f[s1.c] > f[s2.c]; 36 } 37 }; 38 39 priority_queue<state, vector<state>, cmp> Q; 40 41 int cantor(state s) 42 { 43 char ch; 44 int i, j, c, ret; 45 46 ret = 0; 47 for (i = 0; i < N-1; ++i) 48 { 49 c = 0; 50 ch = s.a[i]; 51 for (j = i+1; j < N; ++j) 52 if (s.a[j] < ch) ++c; 53 ret += c*fact[8-i]; 54 } 55 56 return ret; 57 } 58 59 void set_goal(char *s, state *goal) 60 { 61 int i; 62 63 for (i = 0; i < N; ++i) 64 (*goal).a[i] = s[i] - '0'; 65 } 66 67 char bool_inv(state s) 68 { 69 char ch, ret; 70 int i, j; 71 72 ret = 0; 73 for (i = 0; i < N-1; ++i) 74 { 75 if ((ch = s.a[i]) == 0) continue; 76 for (j = i+1; j < N; ++j) 77 if (s.a[j] && s.a[j] < ch) ret = 1 - ret; 78 } 79 80 return ret; 81 } 82 83 84 int heu(state cur, state goal) /* Manhattan 距离, 不含 0 */ 85 { 86 char ch; 87 int i, j, ret; 88 89 ret = 0; 90 for (i = 0; i < N; ++i) 91 { 92 ch = goal.a[i]; 93 //if (ch == 0) continue; 94 for (j = 0; j < N; ++j) 95 { 96 if (cur.a[j] == ch) 97 { 98 ret += abs(j/3 - i/3) + abs(j%3 - i%3); 99 break; 100 } 101 } 102 } 103 104 return ret; 105 } 106 107 int Astar(state start, state goal) 108 { 109 int cc, cn, cg; 110 short int i, x, y, nx, ny; 111 state cur, nst; 112 113 memset(g, 0, sizeof(g)); 114 memset(f, 0, sizeof(f)); 115 memset(p, 0, sizeof(p)); 116 /* memset(vis, 0, sizeof(vis)); */ 117 118 while (!Q.empty()) Q.pop(); 119 120 g[start.c] = 1; /* 用 g[] 代替 vis[] */ 121 f[start.c] = start.h + 1; 122 /* vis[start.c] = 1; */ 123 Q.push(start); 124 125 while (!Q.empty()) 126 { 127 cur = Q.top(); 128 Q.pop(); 129 /* vis[cur.c] = 2; */ 130 if (cur.c == goal.c) {return g[cur.c]-1;} /* 搜索到目标节点, 走的距离应为 g[]-1 */ 131 for (i = 0; cur.a[i] && i < N; ++i) ; 132 x = i / 3; y = i % 3; 133 for (i = 0; i < 4; ++i) 134 { 135 nx = x + dir[i][0]; ny = y + dir[i][1]; 136 if (0<=nx && nx<3 && 0<=ny && ny<3) /* 这里边界判断原来写成了<=3,结果差得很远 */ 137 { 138 nst = cur; 139 nst.a[x*3+y] = cur.a[nx*3+ny]; 140 nst.a[nx*3+ny] = 0; 141 nst.c = cantor(nst); 142 if (g[nst.c] == 0) 143 { 144 p[nst.c].p = cur.c; 145 p[nst.c].d = md[i]; 146 nst.h = heu(nst, goal); 147 g[nst.c] = g[cur.c] + 1; 148 f[nst.c] = g[nst.c] + nst.h; 149 Q.push(nst); 150 /* vis[nst.c] = 1; */ 151 } 152 /* 153 else if (vis[nst.c] == 1 && g[nst.c] > g[cur.c]+1) 154 { 155 p[nst.c].p = cur.c; 156 p[nst.c].d = md[i]; 157 g[nst.c] = g[cur.c] + 1; 158 f[nst.c] = g[nst.c] + nst.h; 159 //Q.push(nst); 160 } 161 */ 162 } 163 } 164 } 165 166 return -1; 167 } 168 169 void print_path(int x) 170 { 171 if (p[x].p == 0) return ; 172 print_path(p[x].p); 173 putchar(p[x].d); 174 } 175 176 bool read(state* s) 177 { 178 int i; 179 char c[5]; 180 181 if (EOF == scanf("%s", c)) return false; 182 else (*s).a[0] = (c[0]=='x' ? 0:c[0]-'0'); 183 for (i = 1; i < N; ++i) 184 { 185 scanf("%s", c); 186 (*s).a[i] = (c[0]=='x' ? 0:c[0]-'0'); 187 } 188 (*s).c = cantor(*s); 189 190 return true; 191 } 192 193 void solve(state start, state goal) 194 { 195 start.h = heu(start, goal); 196 if (bool_inv(start) != bool_inv(goal)) puts("unsolvable"); 197 else 198 { 199 Astar(start, goal); /* 逆序剪枝后,剩下的状态一定有解 */ 200 print_path(goal.c); 201 putchar('\n'); 202 } 203 } 204 205 int main() 206 { 207 state start, goal; 208 209 freopen("in.txt", "r", stdin); 210 freopen("out.txt", "w", stdout); 211 212 // set_goal("123456780", &goal); 213 goal.c = cantor(goal); 214 while (read(&start)) 215 { 216 read(&goal); 217 solve(start, goal); 218 } 219 220 /* printf("time cost %u ms.\n", clock()/CLOCKS_PER_SEC); */ 221 222 return 0; 223 }
//