问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=1077思路:
传说中经典的经典
解法有: 单向BFS,双向BFS,还有A*等启发式搜索算法
今天先写了前两种方法的代码,至于启发式算法待续
判重: 全排列的哈希,详见:
http://www.cppblog.com/Joe/archive/2010/08/06/122410.html代码(单向BFS,110MS):
1 #define RC 3
2 #define STR_LEN 9
3 #define HASH_LEN 362880 /* 9! */
4 const int facs[] = {1, 2, 6, 24, 120, 720, 5040, 40320};
5 const char letters[] = "udlr";
6 const int dx[] = {-1, 1, 0, 0};
7 const int dy[] = {0, 0, -1, 1};
8 char success[] = "123456780";
9 char begin[STR_LEN+1];
10 int success_hash, begin_position;
11 int hash[HASH_LEN];
12 struct EACH {
13 char str[STR_LEN+1];
14 int position;
15 int pre;
16 int dir;
17 } queue[HASH_LEN];
18
19 /* permutation -> number */
20 int
21 hash_func(char *str)
22 {
23 int i, j, cnt, result = 0;
24 for(i=1; i<STR_LEN; i++) {
25 cnt = 0;
26 for(j=0; j<i; j++)
27 if(str[j] > str[i])
28 ++cnt;
29 result += (cnt*facs[i-1]);
30 }
31 return result;
32 }
33
34 void
35 init()
36 {
37 int i;
38 char input[2];
39 memset(hash, 0, sizeof(hash));
40 for(i=0; i<STR_LEN; i++) {
41 scanf("%s", input);
42 begin[i] = input[0];
43 if(begin[i] == 'x') {
44 begin[i] = '0';
45 begin_position = i;
46 }
47 }
48 begin[STR_LEN] = '\0';
49 success_hash = hash_func(success);
50 }
51
52 void
53 output(int index)
54 {
55 if(queue[index].pre == -1)
56 return;
57 output(queue[index].pre);
58 printf("%c", letters[queue[index].dir]);
59 }
60
61 #define ADD(tail, s, pos, p, d) strcpy(queue[tail].str, s); \
62 queue[tail].position = pos; \
63 queue[tail].pre = p; \
64 queue[tail].dir = d;
65
66 #define CHECK(h) if(h == success_hash) { \
67 output(tail); \
68 printf("\n"); \
69 return; \
70 }
71
72 void
73 bfs()
74 {
75 int i, h, head, tail;
76 char nxt[STR_LEN+1];
77 int curx, cury, nxtx, nxty;
78 head = -1;
79 tail = 0;
80 ADD(tail, begin, begin_position, -1, -1);
81 h = hash_func(begin);
82 hash[h] = 1;
83 CHECK(h);
84 while(head < tail) {
85 ++head;
86 curx = queue[head].position/RC;
87 cury = queue[head].position%RC;
88 for(i=0; i<4; i++) {
89 nxtx = curx + dx[i];
90 nxty = cury + dy[i];
91 if(nxtx>=0 && nxtx<RC && nxty>=0 && nxty<RC) {
92 strcpy(nxt, queue[head].str);
93 nxt[queue[head].position] = nxt[nxtx*RC+nxty];
94 nxt[nxtx*RC+nxty] = '0';
95 h = hash_func(nxt);
96 if(!hash[h]) {
97 ++tail;
98 ADD(tail, nxt, nxtx*RC+nxty, head, i);
99 hash[h] = 1;
100 CHECK(h);
101 }
102 }
103 }
104 }
105 printf("unsolvable\n");
106 }
代码(双向BFS,16MS):
1 #define RC 3
2 #define STR_LEN 9
3 #define HASH_LEN 362880 /* 9! */
4 const int facs[] = {1, 2, 6, 24, 120, 720, 5040, 40320};
5 const char letters[] = "udlr";
6 const int pos[] = {-3, 3, -1, 1}; /* up, down, left, right */
7 const int movable[][4] = {0,1,0,1, 0,1,1,1, 0,1,1,0, 1,1,0,1, 1,1,1,1, 1,1,1,0, 1,0,0,1, 1,0,1,1, 1,0,1,0};
8 int hash[2][HASH_LEN];
9 struct EACH {
10 char str[STR_LEN+1];
11 int position, pre, dir, hval;
12 } queue[2][HASH_LEN];
13
14 /* permutation -> number */
15 int
16 hash_func(char *str)
17 {
18 int i, j, cnt, result = 0;
19 for(i=1; i<STR_LEN; i++) {
20 cnt = 0;
21 for(j=0; j<i; j++)
22 if(str[j] > str[i])
23 ++cnt;
24 result += (cnt*facs[i-1]);
25 }
26 return result;
27 }
28
29 void
30 output(int hash_value)
31 {
32 int i, j;
33 char tmp[250];
34 for(i=0; i<HASH_LEN; i++)
35 if(queue[0][i].hval == hash_value)
36 break;
37 j = 0;
38 while(queue[0][i].pre != -1) {
39 tmp[j++] = letters[queue[0][i].dir];
40 i = queue[0][i].pre;
41 }
42 for(i=j-1; i>=0; i--)
43 printf("%c", tmp[i]);
44
45 for(i=0; i<HASH_LEN; i++)
46 if(queue[1][i].hval == hash_value)
47 break;
48 while(queue[1][i].pre != -1) {
49 printf("%c", queue[1][i].dir%2==0 ? letters[queue[1][i].dir+1] : letters[queue[1][i].dir-1]);
50 i = queue[1][i].pre;
51 }
52 }
53
54 #define ADD(index, tail, s, pos, p, d, h) strcpy(queue[index][tail].str, s); \
55 queue[index][tail].position = pos; \
56 queue[index][tail].pre = p; \
57 queue[index][tail].dir = d; \
58 queue[index][tail].hval = h;
59
60 int
61 bfs(char *start_str, int start_pos)
62 {
63 int i, index, h, curp, nxtp, head[2], tail[2];
64 char suc[] = "123456780";
65 char nxt[STR_LEN+1];
66 head[0] = head[1] = -1;
67 tail[0] = tail[1] = 0;
68 h = hash_func(start_str);
69 hash[0][h] = 1;
70 ADD(0, tail[0], start_str, start_pos, -1, -1, h);
71 h = hash_func(suc);
72 hash[1][h] = 1;
73 ADD(1, tail[1], suc, 8, -1, -1, h);
74 while(head[0]<tail[0] && head[1]<tail[1]) {
75 for(index=0; index<2; index++) {
76 ++head[index];
77 curp = queue[index][head[index]].position;
78 for(i=0; i<4; i++) {
79 if(movable[curp][i]) {
80 nxtp = curp + pos[i];
81 strcpy(nxt, queue[index][head[index]].str);
82 nxt[curp] = nxt[nxtp];
83 nxt[nxtp] = '0';
84 h = hash_func(nxt);
85 if(!hash[index][h]) {
86 ++tail[index];
87 ADD(index, tail[index], nxt, nxtp, head[index], i, h);
88 hash[index][h] = 1;
89 }
90 if(hash[1-index][h])
91 return h;
92 }
93 }
94 }
95 }
96 return -1;
97 }
98
99 int
100 main(int argc, char **argv)
101 {
102 int i, sp, h;
103 char input[2], num[STR_LEN+1];
104 for(i=0; i<STR_LEN; i++) {
105 scanf("%s", input);
106 num[i] = input[0];
107 if(num[i]=='x') {
108 num[i] = '0';
109 sp = i;
110 }
111 }
112 num[STR_LEN] = '\0';
113 h = bfs(num, sp);
114 if(h==-1)
115 printf("unsolvable\n");
116 else {
117 output(h);
118 printf("\n");
119 }
120 return 0;
121 }