IOI'94 - Day 2
|-------| |-------| |-------| | | | | | | | |---O | |---O | | O | | | | | | | |-------| |-------| |-------| A B C |-------| |-------| |-------| | | | | | | | O | | O | | O | | | | | | | | | | |-------| |-------| |-------| D E F |-------| |-------| |-------| | | | | | | | O | | O---| | O | | | | | | | | | |-------| |-------| |-------| G H I
The goal is to find a minimal sequence of moves to return all the dials to 12 o'clock. Nine different ways to turn the dials on the clocks are supplied via a table below; each way is called a move. Select for each move a number 1 through 9 which will cause the dials of the affected clocks (see next table) to be turned 90 degrees clockwise.
Move | Affected clocks |
1 | ABDE |
2 | ABC |
3 | BCEF |
4 | ADG |
5 | BDEFH |
6 | CFI |
7 | DEGH |
8 | GHI |
9 | EFHI |
Example
Each number represents a time according to following table:9 9 12 9 12 12 9 12 12 12 12 12 12 12 12 6 6 6 5 -> 9 9 9 8-> 9 9 9 4 -> 12 9 9 9-> 12 12 12 6 3 6 6 6 6 9 9 9 12 9 9 12 12 12
[But this might or might not be the `correct' answer; see below.]
PROGRAM NAME: clocks
INPUT FORMAT
Lines 1-3: | Three lines of three space-separated numbers; each number represents the start time of one clock, 3, 6, 9, or 12. The ordering of the numbers corresponds to the first example above. |
SAMPLE INPUT (file clocks.in)
9 9 12 6 6 6 6 3 6
OUTPUT FORMAT
A single line that contains a space separated list of the shortest sequence of moves (designated by numbers) which returns all the clocks to 12:00. If there is more than one solution, print the one which gives the lowest number when the moves are concatenated (e.g., 5 2 4 6 < 9 3 1 1).
SAMPLE OUTPUT (file clocks.out)
4 5 8 9
————————————————————蛋疼的分割线————————————————————
前言:呜……交了十多次才过。一开始不知道怎么输出路径,后来想起来倒走迷宫的方法了。用两个数组来保存一个点是从哪个点走过来的。一个数组保存父节点的编号,另一个保存方向。暴搜。之后一直在爆内存、数组越界。直到我试出了一个数。
题意:鉴于这道题比较难懂,我解释一下。其实就是给你3*3=9个钟,有九种操作分别可以使某几个时钟顺时针旋转90度(表中给出),输出一个最短的方案,使得9个钟都表示12点。
思路:看懂意思之后我想到了八数码问题。没错,正解就是BFS嘛。在bfs中尝试九种操作,事先写出Move函数,把表中的操作枚举出来。之后再for(int i = 1; i <= 9; i++)。判重依旧利用哈希、挂链法。挂链操作:
h = Hash(a[rear]);
u = head[h];
while(u) {
......
u = next[u];
......
}
next[rear] = head[h];
head[h] = rear;
代码如下:
/*
ID: j.sure.1
PROG: clocks
LANG: C++
*/
/****************************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <string>
#include <iostream>
using namespace std;
/****************************************/
const int N = 400000, HN = 400003;
unsigned char a[N][3][3], e[3][3] = {12, 12, 12, 12, 12, 12, 12, 12, 12}, la_dir[N], dir[N];
int head[HN], next[N];
int fa[N];
int Hash(unsigned char x[3][3])
{
int v = 0;
for(int i = 0; i < 3; i++)
for(int j = 0; j < 3; j++)
v = v * 10 + x[i][j];
return v % HN;
}
bool try_insert(int r)
{
int h = Hash(a[r]);
int u = head[h];
while(u) {
if(!(memcmp(a[u], a[r], sizeof(a[0]))))
return false;
u = next[u];
}
next[r] = head[h];
head[h] = r;
return true;
}
void Move(int op, unsigned char x[3][3])
{
unsigned char &a1 = x[0][0], &a2 = x[0][1], &a3 = x[0][2];
unsigned char &a4 = x[1][0], &a5 = x[1][1], &a6 = x[1][2];
unsigned char &a7 = x[2][0], &a8 = x[2][1], &a9 = x[2][2];
switch(op)
{
case 1: a1 += 3; if(a1 > 12) a1 -= 12;
a2 += 3; if(a2 > 12) a2 -= 12;
a4 += 3; if(a4 > 12) a4 -= 12;
a5 += 3; if(a5 > 12) a5 -= 12; break;
case 2: a1 += 3; if(a1 > 12) a1 -= 12;
a2 += 3; if(a2 > 12) a2 -= 12;
a3 += 3; if(a3 > 12) a3 -= 12; break;
case 3: a2 += 3; if(a2 > 12) a2 -= 12;
a3 += 3; if(a3 > 12) a3 -= 12;
a5 += 3; if(a5 > 12) a5 -= 12;
a6 += 3; if(a6 > 12) a6 -= 12; break;
case 4: a1 += 3; if(a1 > 12) a1 -= 12;
a4 += 3; if(a4 > 12) a4 -= 12;
a7 += 3; if(a7 > 12) a7 -= 12; break;
case 5: a2 += 3; if(a2 > 12) a2 -= 12;
a4 += 3; if(a4 > 12) a4 -= 12;
a5 += 3; if(a5 > 12) a5 -= 12;
a6 += 3; if(a6 > 12) a6 -= 12;
a8 += 3; if(a8 > 12) a8 -= 12; break;
case 6: a3 += 3; if(a3 > 12) a3 -= 12;
a6 += 3; if(a6 > 12) a6 -= 12;
a9 += 3; if(a9 > 12) a9 -= 12; break;
case 7: a4 += 3; if(a4 > 12) a4 -= 12;
a5 += 3; if(a5 > 12) a5 -= 12;
a7 += 3; if(a7 > 12) a7 -= 12;
a8 += 3; if(a8 > 12) a8 -= 12; break;
case 8: a7 += 3; if(a7 > 12) a7 -= 12;
a8 += 3; if(a8 > 12) a8 -= 12;
a9 += 3; if(a9 > 12) a9 -= 12; break;
case 9: a5 += 3; if(a5 > 12) a5 -= 12;
a6 += 3; if(a6 > 12) a6 -= 12;
a8 += 3; if(a8 > 12) a8 -= 12;
a9 += 3; if(a9 > 12) a9 -= 12; break;
}
}
int bfs()
{
memset(head, 0, sizeof(head));
int fron = 1, rear = 2;
while(fron < rear) {
if(!memcmp(a[fron], e, sizeof(e)))
return fron;
for(int i = 1; i <= 9; i++) {
memcpy(&a[rear], &a[fron], sizeof(a[0]));
Move(i, a[rear]);
fa[rear] = fron;
la_dir[rear] = i;
if(try_insert(rear)) {
rear++;
}
}
fron++;
}
return 0;
}
void PR(int cur)
{
int c = 0;
for(;;) {
int tmp = fa[cur];
if(tmp == cur)
break;
dir[c++] = la_dir[cur];
cur = tmp;
}
c--;
while(c > 1) {
c--;
printf("%d ", dir[c]);
}
c--;
printf("%d\n", dir[c]);
}
int main()
{
freopen("clocks.in", "r", stdin);
freopen("clocks.out", "w", stdout);
int input;
for(int i = 0; i < 3; i++)
for(int j = 0; j < 3; j++) {
scanf("%d", &input);
a[1][i][j] = input;
}
int n = bfs();
PR(n);
fclose(stdin);
fclose(stdout);
return 0;
}