程序设计与算法(二)拨钟问题

题目
有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;
}

发布了26 篇原创文章 · 获赞 11 · 访问量 2316

猜你喜欢

转载自blog.csdn.net/qq_41731507/article/details/88805301
今日推荐