题解-拨钟问题

这是一篇关于拨钟问题的解题博客,通过枚举解法寻找将9个时钟指针拨到12点的最短移动序列。讨论了如何利用熄灯问题的思路来解决此问题,分析了各个时钟受影响的操作,以及如何根据当前状态确定后续操作的次数。文章附有C++代码实现。
摘要由CSDN通过智能技术生成

题目

描述

有9个时钟,排成一个3*3的矩阵。

						|-------|    |-------|    |-------|
						|       |    |       |    |   |   |
						|---O   |    |---O   |    |   O   |
						|       |    |       |    |       |
						|-------|    |-------|    |-------|
						    A            B            C    
						
						|-------|    |-------|    |-------|
						|       |    |       |    |       |
						|   O   |    |   O   |    |   O   |
						|   |   |    |   |   |    |   |   |
						|-------|    |-------|    |-------|
						    D            E            F    
						
						|-------|    |-------|    |-------|
						|       |    |       |    |       |
						|   O   |    |   O---|    |   O   |
						|   |   |    |       |    |   |   |
						|-------|    |-------|    |-------|
						    G            H            I    
						               (图 1)

现在需要用最少的移动,将9个时钟的指针都拨到12点的位置。共允许有9种不同的移动。如下表所示,每个移动会将若干个时钟的指针沿顺时针方向拨动90度。

移动    影响的时钟
 1         ABDE
 2         ABC
 3         BCEF
 4         ADG
 5         BDEFH
 6         CFI
 7         DEGH
 8         GHI
 9         EFHI   
输入

9个整数,表示各时钟指针的起始位置,相邻两个整数之间用单个空格隔开。其中,0=12点、1=3点、2=6点、3=9点。

输出

输出一个最短的移动序列,使得9个时钟的指针都指向12点。按照移动的序号从小到大输出结果。相邻两个整数之间用单个空格隔开。

样例输入
3 3 0
2 2 2
2 1 2
样例输出
4 5 8 9

解题思路

这道题是熄灯问题的变种,解决熄灯问题的思路同样可以放到这道题上。

灯的状态有四种,对应数字即0123,其中0就是我们想要的状态(指向12点)。也就是说,无论你对一个钟拨多少次,它都只会展现四种状态,也就是 (初始状态+拨钟次数)%4

除此之外,拨钟的顺序也是不影响最终的结果的。你先拨A钟再拨B钟与先B再A在结果上也没有任何的区别。

不过它与熄灯问题所不同的是,熄灯问题的状态确定方式非常明显,第一行的灯在按过之后会确定下一行灯的状态从而确定对下一行灯进行的操作;而本题的状态之确定却需要仔细地观察题目条件。

在移动的九种操作中,能影响到A钟的操作只有1、2和4,能影响到B钟的操作只有1、2、3和5,而能影响到C钟的是2、3和6。也就是说,如果我们用枚举遍历所有123操作的可能次数的话,剩下的就只有4、5、6操作能够分别单独影响ABC钟。这样我们就能根据执行完123操作后的ABC钟的状态来决定456操作的次数。

同理,456操作的次数确定之后我们就能根据操作完后D和F钟的情况来确定7和9操作的次数了。在1-7、9的操作次数确定以后,我们只需要判断E是否为0加上GHI钟的状态是否相等就可以决定本次所枚举的情况行不行啦。当然题目要求的是最短操作(并不要求顺序),所以还得记得在每次遍历中记录操作再比较长短。

代码

说明:代码语言为C++,其中操作使用一个数组来记录。数组的0-8下标分别对应着1-9操作的次数。代码写的比较简单无脑而且杂乱无章,不喜勿喷~

#include<iostream>
#include<string.h>
using namespace std;

int main()
{
   
    int i = 0;
    int j = 0;
    int minArr[9] = {
   0};
    int minSum = 99999;
    int myClock[9] = {
   0};
    int opr[9] = {
   0};
    int tempClock[9];
    for(i = 0; i < 9; i++) {
   
        cin >> myClock[i];
        tempClock
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值