北京2008的挂钟

28 篇文章 0 订阅
3 篇文章 0 订阅
题目描述

在这里插入图片描述
  在2008北京奥运会雄伟的主会场的墙上,挂着如上图所示的3*3的九个挂钟(一开始指针即时针指向的位置请根据输入数据调整)。然而此次奥运会给与了大家一个机会,去用最少的移动操作改变上面的挂钟的时间全部为12点正(我们只考虑时针)。然而每一次操作并不是任意的,我们必须按照下面给出的列表对于挂钟进行改变。每一次操作我们给而且必须给指定的操作挂钟进行,每一个挂钟顺时针转动90度。列表如下:
操作   指定的操作挂钟
 1     ABDE
 2     ABC
 3     BCEF
 4     ADG
 5     BDEFH
 6     CFI
 7     DEGH
 8     GHI
 9     EFHI

输入数据

  你的程序按照标准的 3∗3 格式读入,一共 9 个 0−3 的数。 0 代表 12 点, 1 代表 3 点, 2 代表 6 点, 3 代表 9 点。
  Your program is to read from standard input. Nine numbers give the start positions of the dials. 0=12 o’clock, 1=3 o’clock, 2=6 o’clock, 3=9 o’clock.
输出数据
  你的程序需要写出标准的输出。输出一个最短的能够使所有挂钟指向 12 点的移动操作序列,中间以空格隔开,最后有空格,加回车。这一条最短操作需要是所有最短操作中最小的,也就是说选择最小的第一个操作数,如果第一个操作数相等,那么选择最小的第二个操作数……以此类推。值得肯定的是,这一条操作序列是唯一的。
  Your program is to write to standard output. Output a shortest sorted sequence of moves (numbers), which returns all the dials to 12 o’clock. You are convinced that the answer is unique.

样例输入

3 3 0
2 2 2
2 1 2

样例输出

4 5 8 9

样例说明

[b]Description[/b]

(Figure 1)

There are nine clocks in a 3*3 array (figure 1). The goal is to return all the dials to 12 o’clock with as few moves as possible. There are nine different allowed ways to turn the dials on the clocks. Each such way is called a move. Select for each move a number 1 to 9. That number will turn the dials 90’ (degrees) clockwise on those clocks which are affected according to figure 2 below.

Move Affected clocks

1     ABDE
2     ABC
3     BCEF
4     ADG
5     BDEFH
6     CFI
7     DEGH
8     GHI
9     EFHI  
(Figure 2)

[b]Input[/b]
Your program is to read from standard input. Nine numbers give the start positions of the dials. 0=12 o’clock, 1=3 o’clock, 2=6 o’clock, 3=9 o’clock.

[b]Output[/b]
Your program is to write to standard output. Output a shortest sorted sequence of moves (numbers), which returns all the dials to 12 o’clock. You are convinced that the answer is unique.

程序分析

恶补搜索之dfs+剪枝。
  我们可以想到每个操作使用四次就会变为原来的样子,所以每个操作使用次数为0~3次。这可以算作一种剪枝(不用搜重复无用的状态)。
  其次我的收获是对于“搜索状态的设计”。怎么说呢。我开始想的是,我从初始状态开始,枚举选用9种中的哪一个操作(若选择次数已经=3就不能选),然后判断该状态是否到达终点,然后进入下一层;当某一层的所有状态都无法到达时,回溯到上一层。可是仔细想想,这样会组成许多重复的状态(因为操作顺序不影响最终效果)。我们可以将所有操作已用的次数记为数字s[],这样只要一次次枚举每个操作用了多少次,就可以不重复地搜到所有情况。

#include"stdafx.h"
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;

// 枚举+深搜
// 因为递归深度为9,不用担心内存溢出
// 如果对每个操作,进行4次以上包含4次的操作,指针落到的位置与0次或1次或2次或3次操作的效果相同

// 将所有操作已用的次数记为数字s[],这样只要一次次枚举每个操作用了多少次,就可以不重复地搜到所有情况。
int init[10], temp[10], s[10];
int judge[9][9] = { { 1,1,0,1,1,0,0,0,0 },	// 操作1	ABDE
					{ 1,1,1,0,0,0,0,0,0 },	// 操作2	ABC
					{ 0,1,1,0,1,1,0,0,0 },	// 操作3	BCEF
					{ 1,0,0,1,0,0,1,0,0 },	// 操作4	ADG
					{ 0,1,0,1,1,1,0,1,0 },	// 操作5	BDEFH
					{ 0,0,1,0,0,1,0,0,1 },	// 操作6	CFI
					{ 0,0,0,1,1,0,1,1,0 },	// 操作7	DEGH
					{ 0,0,0,0,0,0,1,1,1 },	// 操作8	GHI
					{ 0,0,0,0,1,1,0,1,1 }	// 操作9	EFHI
};
bool dfs(int op)
{
	int flag = 1;
	for (int i = 0; i<9; i++)	// 这句话很重要,因为是每次枚举出的是不同操作的数目,作用的是原始挂钟状态
		temp[i] = init[i];
	for (int j = 0; j<9; j++)
		for (int i = 0; i<9; i++)
			temp[j] = (temp[j] + judge[i][j] * s[i]) % 4;	// 改变9个挂钟的状态
	for (int i = 0; i<9; i++){
		if (temp[i]){	 // 若有不是12点的钟
			flag = 0; 
			break; 
		}
	}
	if (flag){			// 若所有的9个钟都调整到了12点
		for (int i = 0; i < 9; i++)
			for (int j = 0; j < s[i]; j++)
				cout << i + 1 << " ";
		cout << endl;
		return true;
	}
	if (op >= 9)					// 9种方式全部搜完
		return false;
	for (int i = 0; i<4; i++){	
		s[op] = i;  // 将所有操作已用的次数记为数字s[],这样只要一次次枚举每个操作用了多少次,就可以不重复地搜到所有情况。
		if (dfs(op + 1))			//深搜
			return true;
	}
	return false;
}
int main(){
	for (int i = 0; i<9; i++)
		cin >> init[i];
	dfs(0);
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值