USACO-cha1-sec1.4 The Clocks

The Clocks
IOI'94 - Day 2
Consider nine clocks arranged in a 3x3 array thusly:
|-------|    |-------|    |-------|    
|       |    |       |    |   |   |    
|---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.

MoveAffected clocks
1ABDE
2ABC
3BCEF
4ADG
5BDEFH
6CFI
7DEGH
8GHI
9EFHI

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;
}
	


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值