試題請參見: 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;
}