试题请参见: https://vijos.org/p/1016
题目概述
在2008北京奥运会雄伟的主会场的墙上, 挂着如上图所示的3*3的九个挂钟(一开始指针即时针指向的位置请根据输入数据调整). 然而此次奥运会给与了大家一个机会, 去用最少的移动操作改变上面的挂钟的时间全部为12点正(我们只考虑时针). 然而每一次操作并不是任意的, 我们必须按照下面给出的列表对于挂钟进行改变. 每一次操作我们给而且必须给指定的操作挂钟进行, 每一个挂钟顺时针转动90度. 列表如下:
操作 | 指定的操作挂钟 |
---|---|
1 | ABDE |
2 | ABC |
3 | BCEF |
4 | ADG |
5 | BDEFH |
6 | CFI |
7 | DEGH |
8 | GHI |
9 | EFHI |
解题思路
这题解法有很多, 但是我们注意到就算穷举运算量也并不大. 于是我们就使用穷举.
有一个简单的”剪枝”, 每一个操作的最大次数为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;
}