拨钟问题

来源:互联网 发布:重庆市网络知识竞赛 编辑:程序博客网 时间:2024/04/29 18:20

描述

有9个时钟,排成一个3*3的矩阵。

|-------|    |-------|    |-------||       |    |       |    |   |   ||---O   |    |---O   |    |   O   ||       |    |       |    |       ||-------|    |-------|    |-------|    A            B            C    |-------|    |-------|    |-------||       |    |       |    |       ||   O   |    |   O   |    |   O   ||   |   |    |   |   |    |   |   ||-------|    |-------|    |-------|    D            E            F    |-------|    |-------|    |-------||       |    |       |    |       ||   O   |    |   O---|    |   O   ||   |   |    |       |    |   |   ||-------|    |-------|    |-------|    G            H            I    (图 1)

现在需要用最少的移动,将9个时钟的指针都拨到12点的位置。共允许有9种不同的移动。如下表所示,每个移动会将若干个时钟的指针沿顺时针方向拨动90度。


移动    影响的时钟  1         ABDE 2         ABC 3         BCEF 4         ADG 5         BDEFH 6         CFI 7         DEGH 8         GHI 9         EFHI    

输入
9个整数,表示各时钟指针的起始位置,相邻两个整数之间用单个空格隔开。其中,0=12点、1=3点、2=6点、3=9点。
输出
输出一个最短的移动序列,使得9个时钟的指针都指向12点。按照移动的序号从小到大输出结果。相邻两个整数之间用单个空格隔开。
样例输入
3 3 0 2 2 2 2 1 2 
样例输出
4 5 8 9 


思路描述:

      一个移动,如果做四次相当于没有做,所以每种移动最多做3次。先确定123步做的次数,枚举出所有种情况,则只有第4步能影响A,第5步能影响B,第6步能影响C,第7步能影响D,第9步能影响F,则根据ABCDF的情况可以分别确定45679步的次数,再通过G的情况确定8步次数,检查是否每一个钟都为12点,成功则与之前的成功情况比较,如果步数更少则取代之前情况。完成所有情况后,排序输出。


代码如下:

#include <iostream>#include <string.h>using namespace std;int OriRotateTime[9];int RotateTime[9];int change[9][9]={{-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 step=0;//步数计数int minstep=36;//最小步数计数int minmovestep[27];//步数输出数组int movestep[27];//步数数组void refresh(int s)//更新时钟状态{for(int i=0;i<9;i++){if(RotateTime[i]+change[s][i]>=0)RotateTime[i]=RotateTime[i]+change[s][i];elseRotateTime[i]=RotateTime[i]+change[s][i]+4;}}void Result()//结果处理,排序输出{int mid;for(int i=0;i<minstep;i++){for(int j=i+1;j<minstep;j++){if(minmovestep[i]>minmovestep[j]){mid=minmovestep[i];minmovestep[i]=minmovestep[j];minmovestep[j]=mid;}}}for(int i=0;i<minstep;i++){cout<<minmovestep[i]<<" ";}}void Select(){for(int m=0;m<4;m++)//确定4567步的次数{int t=RotateTime[m];while(t>0){movestep[step++]=m+4;refresh(m+3);t--;}}int t=0;t=RotateTime[5];while(t>0)//确定9{movestep[step++]=9;refresh(8);t--;}t=RotateTime[6];while(t>0)//确定8{movestep[step++]=8;refresh(7);t--;}if(RotateTime[4]==0&&RotateTime[7]==0&&RotateTime[8]==0)//检查是否成功{if(step<minstep)//与之前最小值比较{minstep=step;memcpy(minmovestep,movestep,sizeof(movestep));}}memcpy(RotateTime,OriRotateTime,sizeof(RotateTime));//恢复初值开始下一种情况for(int i=0;i<27;i++){movestep[i]=0;}step=0;}int main(){for(int i=0;i<9;i++){char a;cin>>a;switch(a){case '0':OriRotateTime[i]=0;break;case '1':OriRotateTime[i]=3;break;case '2':OriRotateTime[i]=2;break;case '3':OriRotateTime[i]=1;break;}}memcpy(RotateTime,OriRotateTime,sizeof(RotateTime));for(int i=0;i<4;i++){for(int j=0;j<4;j++){for(int k=0;k<4;k++)//确定123步的次数{for(int s=i;s>0;s--)//更新1步的操作{movestep[step++]=1;refresh(0);}for(int s=j;s>0;s--)//更新2步的操作{movestep[step++]=2;refresh(1);}for(int s=k;s>0;s--)//更新3步的操作{movestep[step++]=3;refresh(2);}Select();}}}Result();return 0;}


原创粉丝点击