Colour Hash |
This puzzle consists of two wheels. Both wheels can rotate both clock and counter-clockwise. They contain 21 coloured pieces, 10 of which are rounded triangles and 11 of which are separators. Figure 1 shows the final position of each one of the pieces. Note that to perform a one step rotation you must turn the wheel until you have advanced a triangle and a separator.
Figure 1. Final puzzle configuration
Your job is to write a program that reads the puzzle configuration and prints the minimum sequence of movements required to reach the final position. We will use the following integer values to encode each type of piece:
0 | grey separator |
1 | yellow triangle |
2 | yellow separator |
3 | cyan triangle |
4 | cyan separator |
5 | violet triangle |
6 | violet separator |
7 | green triangle |
8 | green separator |
9 | red triangle |
10 | red separator |
A puzzle configuration will be described using 24 integers, the first 12 to describe the left wheel configuration and the last 12 for the right wheel. The first integer represents the bottom right separator of the left wheel and the next eleven integers describe the left wheel clockwise. The thirteenth integer represents the bottom left separator of right wheel and the next eleven integers describe the right wheel counter-clockwise.
The final position is therefore encoded like:
If for instance we rotate the left wheel clockwise one position from the final configuration (as shown in Figure 2) the puzzle configuration would be encoded like:
Figure 2. The puzzle after rotating the left wheel on step clockwise from the final configuration.
Input for your program consists of several puzzles. The first line of the input will contain an integer n specifying the number of puzzles. There will then be n lines each containing 24 integers separated with one white space, describing the initial puzzle configuration as explained above.
For each configuration your program should output one line with just one number representing the solution. Each movement is encoded using one digit from 1 to 4 in the following way:
1 | Left Wheel Clockwise rotation |
2 | Right Wheel Clockwise rotation |
3 | Left Wheel Counter-Clockwise rotation |
4 | Right Wheel Counter-Clockwise rotation |
No space should be printed between each digit. Since multiple solutions could be found, you should print the solution that is encoded as the smallest number. The solution will never require more than 16 movements.
If no solution is found you should print ``NO SOLUTION WAS FOUND IN 16 STEPS". If you are given the final position you should print ``PUZZLE ALREADY SOLVED".
3 0 3 4 3 0 5 6 5 0 1 2 1 0 7 8 7 0 9 10 9 0 1 2 1 0 3 4 5 0 3 6 5 0 1 2 1 0 7 8 7 0 9 10 9 0 1 2 1 0 9 4 3 0 5 6 5 0 1 2 1 0 7 8 7 0 9 10 3 0 1 2 1
PUZZLE ALREADY SOLVED 1434332334332323 NO SOLUTION WAS FOUND IN 16 STEPS
题目大意:给出一个彩色转盘的序列, 转盘的操作有1、左边顺时针2、右边顺时针3、左边逆时针4、左边顺时针。要求在16步之内由给出的转盘状态旋转到初始转态(题目给出), 不能在16步之内完成的和已经完成的输出分别为“NO SOLUTION WAS FOUND IN 16 STEPS", " PUZZLE ALREADY SOLVED".
解题思路:因为题目的限制为16层, 靠单向的bfs为超内存, 所以可以考虑双向BFS,由终点向4个步骤走8步,记录(我将这个步骤放在了循环外面,耗时较少 ),注意输出时要将命令逆序而且1与3对应,2与4 对应。
一开始距离上限搞错了,一直的不到结果,所以以后做题一定要细心啊。
#include <stdio.h> #include <string.h> typedef int State[24]; const int MAXN = 100008; const State begin = {0, 3, 4, 3, 0, 5, 6, 5, 0, 1, 2, 1, 0, 7, 8, 7, 0, 9, 10, 9, 0, 1, 2, 1}; const int dir[4][2] = {{0, 0}, {12, 1}, {0, 1}, {12, 0}}; const int chan[5] = {0, 3, 4, 1, 2}; struct coor { State total; char order[10]; }que[2][MAXN]; int head[2][MAXN], next[2][MAXN], dist[2][MAXN]; int flag, aid, over; State gohead; void turn(int x, int id, int k, int sex) { coor& end = que[sex][k]; if (id) { int t1 = end.total[x], t2 = end.total[x + 1]; for (int i = 0; i < 10; i++) end.total[i + x] = end.total[x + i + 2]; end.total[x + 10] = t1; end.total[x + 11] = t2; } else { int t1 = end.total[x + 10], t2 = end.total[x + 11]; for (int i = x + 11; i > x + 1; i--) { end.total[i] = end.total[i - 2]; } end.total[x] = t1; end.total[x + 1] = t2; } if (x) { for (int i = 0; i < 3; i++) end.total[9 + i] = end.total[21 + i]; } else { for (int i = 0; i < 3; i++) end.total[21 + i] = end.total[9 + i]; } } int hash(coor now) { int sum = 0; for (int i = 0; i < 24; i++) sum = sum * 5 + now.total[i]; return sum % MAXN; } bool tryInsert(int cur, int sex, int k) { int h = hash(que[k][cur]); int u = head[sex][h]; while (u) { if (memcmp(que[sex][u].total, que[k][cur].total, sizeof(que[k][cur].total)) == 0) { if (k + sex == 1) { flag = 1; aid = u; return true; } else return false; } u = next[sex][u]; } if (sex == k) { next[sex][cur] = head[sex][h]; head[sex][h] = cur; return true; } return false; } void bfs(int sex) { int front = 1, rear = 2; memset(head[sex], 0, sizeof(head[sex])); memcpy(que[sex][front].total, gohead, sizeof(begin)); dist[sex][front] = 0; tryInsert(front, sex, sex); while (front < rear) { coor& now = que[sex][front]; if (dist[sex][front] > 8) return; if (tryInsert(front, 1 - sex, sex)) { over = front; return; } for (int i = 0; i < 4; i++) { coor& net = que[sex][rear]; net = now; dist[sex][rear] = dist[sex][front] + 1; turn(dir[i][0], dir[i][1], rear, sex); net.order[dist[sex][front]] = i + 1; if (tryInsert(rear, 1 - sex, sex)) { over = rear; return; } if (tryInsert(rear, sex, sex)) rear++; } front++; } } int main() { memcpy(gohead, begin, sizeof(begin)); bfs(0); int cas; scanf("%d", &cas); while (cas--) { // Init; flag = aid = over = 0; for (int i = 0; i < 24; i++) scanf("%d", &gohead[i]); bfs(1); if (flag && dist[0][aid] + dist[1][over] <= 16) { if (dist[0][aid] + dist[1][over]){ for (int i = 0; i < dist[1][over]; i++) printf("%d", que[1][over].order[i]); for (int i = dist[0][aid] - 1; i >= 0; i--) printf("%d", chan[que[0][aid].order[i]]); printf("\n"); } else printf("PUZZLE ALREADY SOLVED\n"); } else printf("NO SOLUTION WAS FOUND IN 16 STEPS\n"); } return 0; }