题目
有9个时钟,排成一个3*3的矩阵。
现在需要用最少的移动,将9个时钟的指针都拨到12点的位置。共允许有9种不同的移动。如下表所示,每个移动会将若干个时钟的指针沿顺时针方向拨动90度。
输入
9个整数,表示各时钟指针的起始位置,相邻两个整数之间用单个空格隔开。其中,0=12点、1=3点、2=6点、3=9点。
输出
输出一个最短的移动序列,使得9个时钟的指针都指向12点。按照移动的序号从小到大输出结果。相邻两个整数之间用单个空格隔开。
样例输入
3 3 0
2 2 2
2 1 2
样例输出
4 5 8 9
思路
一共有九种拨方法,每种方法最多只使用四次才满足最少拨动次数的要求,所以暴力搜索所有情况就行了,每使用一种拨动方法,受该方法影响的时钟就加一,也就是说某种方法使用了几次,受这种拨动方法影响的钟就加几,比如拨一次方法1,A,B,D,E的位置就加一,对应代码里的 tmp[0],tmp[1],tmp[3],tmp[4]加一,又因为一个钟受多种方法影响,但每个钟是一圈圈的循环转,从 0变到3后又回到0,故每次的枚举要对所有方法和取4的模,并且 49 = 262144,问题不大,不会超时,最后只要从小到大输出使用的方法数目就OK啦。借鉴了之前找到的一个好代码
代码
#include <iostream>
#include <cstring>
using namespace std;
bool isOk(int tmp[]){
for(int i=0;i<9;++i){
if(tmp[i]!=0) return false;
}
return true;
}
void oj_1_2(){
int a[10];
for(int i=0;i<9;++i)
{
cin>>a[i];
}
int tmp[10];
memset(tmp,0,sizeof(tmp));
for(int m1=0;m1<4;++m1){
for(int m2=0;m2<4;++m2){
for(int m3=0;m3<4;++m3){
for(int m4=0;m4<4;++m4){
for(int m5=0;m5<4;++m5){
for(int m6=0;m6<4;++m6){
for(int m7=0;m7<4;++m7){
for(int m8=0;m8<4;++m8){
for(int m9=0;m9<4;++m9)
{
tmp[0]=(a[0]+m1+m2+m4)%4;//拨动1,2,4都会影响 到A,下面类似
tmp[1]=(a[1]+m1+m2+m3+m5)%4;//B
tmp[2]=(a[2]+m2+m3+m6)%4;//C
tmp[3]=(a[3]+m1+m4+m5+m7)%4;//D
tmp[4]=(a[4]+m1+m3+m5+m7+m9)%4;//E
tmp[5]=(a[5]+m3+m5+m6+m9)%4;//F
tmp[6]=(a[6]+m4+m7+m8)%4;//G
tmp[7]=(a[7]+m5+m7+m8+m9)%4;//H
tmp[8]=(a[8]+m6+m8+m9)%4;//I
if(isOk(tmp)){//因为是从小到大枚举,所以最先满足的肯定是最短的移动序列
for(int i=0;i<m1;++i) cout<<"1 ";
for(int i=0;i<m2;++i) cout<<"2 ";
for(int i=0;i<m3;++i) cout<<"3 ";
for(int i=0;i<m4;++i) cout<<"4 ";
for(int i=0;i<m5;++i) cout<<"5 ";
for(int i=0;i<m6;++i) cout<<"6 ";
for(int i=0;i<m7;++i) cout<<"7 ";
for(int i=0;i<m8;++i) cout<<"8 ";
for(int i=0;i<m9;++i) cout<<"9 ";
cout<<endl;
goto END;
}
}
}
}
}
}
}
}
}
}
END:
return;
}
int main(){
oj_1_2();
return 0;
}
官方代码
//BL2814 拨钟问题 by Guo Wei
#include <iostream>
#include <bitset>
#include <algorithm>
#include <functional>
#include <cstring>
using namespace std;
int oriClocks[9];
int clocks[9];
const char* moves[9] = { "ABDE","ABC","BCEF","ADG","BDEFH","CFI","DEGH","GHI","EFHI" };
int moveTimes[9] = { 0 };
int result[9];
int minTimes = 1 << 30;
void Enum(int n)
{
if (n >= 9) {
memcpy(clocks, oriClocks, sizeof(clocks));
int totalTimes = 0;
for (int i = 0; i < 9; ++i) { //依次进行9种移动
if (moveTimes[i]) {
for (int k = 0; moves[i][k]; ++k) {
clocks[moves[i][k] - 'A'] = (clocks[moves[i][k] - 'A'] + moveTimes[i]) % 4;
totalTimes += moveTimes[i];
}
}
}
int i;
for (i = 0; i < 9; ++i)
if (clocks[i])
break;
if (i == 9) {
if (minTimes > totalTimes) {
minTimes = totalTimes;
memcpy(result, moveTimes, sizeof(result));
}
}
return;
}
for (int i = 0; i < 4; ++i) {
moveTimes[n] = i;
Enum(n + 1);
}
return;
}
int main()
{
for (int i = 0; i < 9; ++i)
cin >> oriClocks[i];
Enum(0);
for (int i = 0; i < 9; ++i)
for (int k = 0; k < result[i]; ++k)
cout << i + 1 << " ";
return 0;
}