算法思路:
假设时钟指针位置对应的值为clock_time,那么顺时针旋转90°就是clock_time = (clock_time+1)%4 这一组时针就用一个数组表示。9种操作对应一个二维数组。
这一题实质类似熄灯问题和画家问题。其共通点在于:操作对环境的改变是无序的,每个操作都会影响到周围的状态。同时每一种操作都有周期性限制,也即最多需要几次操作,多于这个次数产生循环。
熄灯问题中,每个灯最多熄灯一次,因为灯只有两种状态,并且循环。而这里,有4种循环的状态,因此每个移动操作顶多使用3次。
我们对移动方法1,2,3进行枚举,每种方法无非实施0-3次,也即一共4^3=64种情况。这些情况之间并非没有关系。例如,我们确定了1,2,3的情况数,那么得到一个灯A,B,C的状态,而只有移动4能够改变A,移动5能够改变B,移动6能够改变C,那么移动4-6的次数也确定了。同样,这时只有移动7能够改变D,移动9能够改变F,这时移动7和9的次数也确定了。最后,时钟A,B,C,D,F都已经到达12点,E,G,H,I还没确定,只剩下移动8能够改变GHI,所以只要检查E是否已经到达12点以及,GHI的时钟数是否相等就行了。最后找到一个移动次数最小的情况。
这题也可以用暴力搜索,因为最多有4^9个组合,不会超时。
这题还可以列出一个方程组,九个未知数,通过高斯消元法来解方程组。
代码:
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
int initial_clocks[10]={0}, adjusted_clocks[10]={0}, op[10]={0};
vector<int> perfect_adjust;
const int operations[10][10] =
{
{0},
// A B C D E F G H I
{0, 1, 1, 0, 1, 1, 0, 0, 0, 0}, //op1: ABDE
{0, 1, 1, 1, 0, 0, 0, 0, 0, 0}, //op2: ABC
{0, 0, 1, 1, 0, 1, 1, 0, 0, 0}, //op3: BCEF
{0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, //op4: ADG
{0, 0, 1, 0, 1, 1, 1, 0, 1, 0}, //op5: BDEFH
{0, 0, 0, 1, 0, 0, 1, 0, 0, 1}, //op6: CFI
{0, 0, 0, 0, 1, 1, 0, 1, 1, 0}, //op7: DEGH
{0, 0, 0, 0, 0, 0, 0, 1, 1, 1}, //op8: GHI
{0, 0, 0, 0, 0, 1, 1, 0, 1, 1} //op9: EFHI
};
/*
调整时钟:
参数:
op_num:调整方式(9种)
op_counts:操作次数
*/
void operate(int op_num, int op_counts) {
for(int k=1; k<=9; k++) {
adjusted_clocks[k] += operations[op_num][k]*op_counts;
adjusted_clocks[k] %= 4;
}
}
int guess() {
op[4]=(4-adjusted_clocks[1])%4;
operate(4, op[4]);
op[5]=(4-adjusted_clocks[2])%4;
operate(5, op[5]);
op[6]=(4-adjusted_clocks[3])%4;
operate(6, op[6]);
op[7]=(4-adjusted_clocks[4])%4;
operate(7, op[7]);
op[8]=(4-adjusted_clocks[7])%4;
operate(8, op[8]);
if (adjusted_clocks[5]==adjusted_clocks[6] && adjusted_clocks[5]==adjusted_clocks[8] && adjusted_clocks[5]==adjusted_clocks[9]){
op[9] = (4-adjusted_clocks[9])%4;
operate(9, op[9]);
int steps=0;
for (int k=1; k<=9; k++) {
steps += op[k];
}
return steps;
}
return 101;
}
int enumerate() {
int c=0;
int minsteps=101;
int steps=0;
while(c<64) {
op[3]=c/16;
op[2]=c%16/4;
op[1]=c%4;
memcpy(adjusted_clocks, initial_clocks, sizeof(initial_clocks));
operate(3, op[3]);
operate(2, op[2]);
operate(1, op[1]);
steps = guess();
if (steps<minsteps) {
minsteps = steps;
perfect_adjust.clear();
for(int k=1; k<=9; k++){
while(op[k]--) {
perfect_adjust.push_back(k);
}
}
}
c++;
}
return minsteps;
}
int main() {
for (int k=1; k<10; k++){
cin >> initial_clocks[k];
}
if (enumerate()<101){
for (int k=0; k<perfect_adjust.size(); k++){
cout << perfect_adjust.at(k) << ' ';
}
}
return 0;
}