拨钟问题
传送门:http://bailian.openjudge.cn/practice/2814?lang=en_US
拨钟问题,画家问题,熄灯问题,这三个题有共同的特点:
1.每个开关或者移动的步数是有次数限制的。拨钟问题移动次数最多为4,因为移动4次跟不移m动一样,画家问题和熄灯问题次数为2,因为开关按两次跟没按一样。
2.移动顺序或者按开关的顺序不重要。都是为了达到目标状态,先按哪个开关和后按哪个开关不影响最终结果。
3.每次按开关或者移动或影响周围环境。
下面谈谈拨钟问题:
一共有9种移动,每种移动会影响多个钟,最后要求所有钟拨到12点的位置。
每个钟有一个开始状态0到3,其中,0=12点、1=3点、2=6点、3=9点。最后要求到达12点的位置也就是目标状态是每个钟=0。
研究一下9种移动:
移动 影响的时钟
1 ABDE
2 ABC
3 BCEF
4 ADG
5 BDEFH
6 CFI
7 DEGH
8 GHI
9 EFHI
这样看可能看不出来啥,把它转换一下:
时钟 会被哪些移动影响
A 124
B 1235
C 236
D 1457
E 13579
F 3569
G 478
H 5789
I 689
这样就很清楚了,用int a[10]记录每个时钟的初始状态,int move[10]记录9种移动的次数,可以枚举9种移动的次数(最多为4),
目标是每个钟经过一系列移动后达到12点,即(a[i]+move[1~9])%4==0,一定要余4,因为表针经过移动后可能会超过一圈。
要使移动序列最短,也就是要使移动次数总和最小,需要设置一个全局变量和全局数组记录最小次数和相应的移动序列。
1 #include<iostream> 2 #include<string.h> 3 using namespace std; 4 int main() 5 { 6 int a[11]; 7 int change[11]; 8 int best[11]; 9 int minCount = 999999; 10 for(int i = 1;i<=9;++i) 11 { 12 cin >>a[i]; 13 } 14 memset(change,0,sizeof(change));//把change数组里的元素全部初始化为0 15 int sum = 0; 16 //每种移动最多就能进行4次 17 18 for(change[1] = 0;change[1]<4;change[1]++) 19 for(change[2] = 0;change[2]<4;change[2]++) 20 for(change[3] = 0;change[3]<4;change[3]++) 21 for(change[4] = 0;change[4]<4;change[4]++) 22 for(change[5] = 0;change[5]<4;change[5]++) 23 for(change[6] = 0;change[6]<4;change[6]++) 24 for(change[7] = 0;change[7]<4;change[7]++) 25 for(change[8] = 0;change[8]<4;change[8]++) 26 for(change[9] = 0;change[9]<4;change[9]++) 27 { 28 sum = 0; 29 sum+= (a[1]+change[1]+change[2]+change[4])%4;//A 30 sum+= (a[2]+change[1]+change[2]+change[3]+change[5])%4;//B 31 sum+= (a[3]+change[2]+change[3]+change[6])%4;//C 32 sum+= (a[4]+change[1]+change[4]+change[5]+change[7])%4;//D 33 sum+= (a[5]+change[1]+change[3]+change[5]+change[7]+change[9])%4;//E 34 sum+= (a[6]+change[3]+change[5]+change[6]+change[9])%4;//F 35 sum+= (a[7]+change[4]+change[7]+change[8])%4;//G 36 sum+= (a[8]+change[5]+change[7]+change[8]+change[9])%4;//H 37 sum+= (a[9]+change[6]+change[8]+change[9])%4;//I 38 if(sum == 0)//要求最短移动序列 39 { 40 int count = 0; 41 for(int j=1;j<=9;j++) 42 { 43 count += change[j]; 44 } 45 if(count < minCount) 46 { 47 minCount = count; 48 memcpy(best,change,sizeof(change)); 49 } 50 for(int j=1;j<=9;j++) 51 { 52 while(best[j]--) 53 { 54 cout << j<<" "; 55 } 56 } 57 } 58 } 59 return 0; 60 }