八数码(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 }

//

posted on 2012-05-24 23:49  getgoing  阅读(1301)  评论(0编辑  收藏  举报

导航