Vijos1016.北京2008的挂钟

试题请参见: https://vijos.org/p/1016

题目概述

Vijos-1016

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

操作指定的操作挂钟
1ABDE
2ABC
3BCEF
4ADG
5BDEFH
6CFI
7DEGH
8GHI
9EFHI

解题思路

这题解法有很多, 但是我们注意到就算穷举运算量也并不大. 于是我们就使用穷举.
有一个简单的”剪枝”, 每一个操作的最大次数为3次(即[0, 4)). 因为当时钟被调整到4次之后又会回到原点, 这显然不是最优解.

遇到的问题

一些非常低级的小问题:

  • 循环变量没有初始化
  • 输出的时候写错了循环变量等

源代码

#include <iostream>

const size_t NUMBER_OF_CLOCKS           = 9;
const size_t NUMBER_OF_OPERATIONS       = 9;
/**
 * 最大操作次数.
 * 由于操作4次会回到原点, 没有必要继续搜索.
 */
const size_t MAX_NUMBER_OF_OPERATIONS   = 4;

/**
 * 获取当前对各个时钟操作的次数.
 * @return 对各个时钟操作的次数
 */
int getOperationTimes(int* operations) {
    int operationTimes = 0;

    for ( size_t i = 0; i < NUMBER_OF_CLOCKS; ++ i ) {
        operationTimes += operations[i];
    }
    return operationTimes;
}

/**
 * 获取最优的调整方案
 * @param  clocks - 当前每个时钟的时间([0, 4)的整数)
 * @param  bestOperations - 对各个时钟最佳操作的次数
 * @return 每个操作进行次数的数组
 */
void getBestSolution(int* clocks, int* bestOperations) {
    /**
     * 存储时钟的初始状态.
     * 用于回溯, 在搜索失败后的rollback.
     */
    int mirrorClocks[NUMBER_OF_CLOCKS] = {0};

    /**
     * 存储对时钟的操作.
     */
    int operations[NUMBER_OF_OPERATIONS][NUMBER_OF_CLOCKS] = {
        { 1, 1, 0, 1, 1, 0, 0, 0, 0 },
        { 1, 1, 1, 0, 0, 0, 0, 0, 0 },
        { 0, 1, 1, 0, 1, 1, 0, 0, 0 },
        { 1, 0, 0, 1, 0, 0, 1, 0, 0 },
        { 0, 1, 0, 1, 1, 1, 0, 1, 0 },
        { 0, 0, 1, 0, 0, 1, 0, 0, 1 },
        { 0, 0, 0, 1, 1, 0, 1, 1, 0 },
        { 0, 0, 0, 0, 0, 0, 1, 1, 1 },
        { 0, 0, 0, 0, 1, 1, 0, 1, 1 }
    };

    /**
     * 存储当前对各时钟操作的计数.
     * 记录对每个时钟操作的次数.
     */
    int currentOperations[NUMBER_OF_CLOCKS] = {0};

    for ( size_t i = 0; i < NUMBER_OF_CLOCKS; ++ i ) {
        mirrorClocks[i] = clocks[i];
    }

    for ( currentOperations[0] = 0 ; currentOperations[0] < MAX_NUMBER_OF_OPERATIONS; ++ currentOperations[0] ) {
        for ( currentOperations[1] = 0 ; currentOperations[1] < MAX_NUMBER_OF_OPERATIONS; ++ currentOperations[1] ) {
            for ( currentOperations[2] = 0 ; currentOperations[2] < MAX_NUMBER_OF_OPERATIONS; ++ currentOperations[2] ) {
                for ( currentOperations[3] = 0 ; currentOperations[3] < MAX_NUMBER_OF_OPERATIONS; ++ currentOperations[3] ) {
                    for ( currentOperations[4] = 0 ; currentOperations[4] < MAX_NUMBER_OF_OPERATIONS; ++ currentOperations[4] ) {
                        for ( currentOperations[5] = 0 ; currentOperations[5] < MAX_NUMBER_OF_OPERATIONS; ++ currentOperations[5] ) {
                            for ( currentOperations[6] = 0 ; currentOperations[6] < MAX_NUMBER_OF_OPERATIONS; ++ currentOperations[6] ) {
                                for ( currentOperations[7] = 0 ; currentOperations[7] < MAX_NUMBER_OF_OPERATIONS; ++ currentOperations[7] ) {
                                    for ( currentOperations[8] = 0 ; currentOperations[8] < MAX_NUMBER_OF_OPERATIONS; ++ currentOperations[8] ) {
                                        // Rollback
                                        for ( size_t i = 0; i < NUMBER_OF_CLOCKS; ++ i ) {
                                            clocks[i] = mirrorClocks[i];
                                        }

                                        bool isSuccessful = true;
                                        for ( size_t i = 0; i < NUMBER_OF_CLOCKS; ++ i ) {
                                            for ( size_t j = 0; j < NUMBER_OF_OPERATIONS; ++ j ) {
                                                clocks[i] += currentOperations[j] * operations[j][i];
                                            }
                                            clocks[i] %= 4;

                                            if ( clocks[i] != 0 ) {
                                                isSuccessful = false;
                                                break;
                                            }
                                        }

                                        if ( !isSuccessful ) {
                                            continue;
                                        }
                                        // Save the solution
                                        int currentOperationTimes = getOperationTimes(currentOperations);
                                        int bestOperationTimes = getOperationTimes(bestOperations);
                                        if ( currentOperationTimes < bestOperationTimes ) {
                                            for ( size_t i = 0; i < NUMBER_OF_OPERATIONS; ++ i ) {
                                                bestOperations[i] = currentOperations[i];
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

int main() {
    /**
     * 存储时钟当前的状态.
     * 在搜索时不断改变.
     */
    int clocks[NUMBER_OF_CLOCKS] = {0};

    /**
     * 存储当前对各时钟操作计数的最优解.
     */
    int bestOperations[NUMBER_OF_OPERATIONS] = { 10, 10, 10, 10, 10, 10, 10, 10, 10 };

    for ( size_t i = 0; i < NUMBER_OF_CLOCKS; ++ i ) {
        std::cin >> clocks[i];
    }

    getBestSolution(clocks, bestOperations);

    for ( size_t i = 0; i < NUMBER_OF_OPERATIONS; ++ i ) {
        for ( int j = 0; j < bestOperations[i]; ++ j ) {
            std::cout << ( i + 1 ) << " ";
        }
    }
    std::cout << std::endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值