Vijos1016.北京2008的掛鐘

試題請參見: https://vijos.org/p/1016

題目概述

Vijos-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;
}
發佈了50 篇原創文章 · 獲贊 1 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章