The Clocks
一组9面钟的初始时间点数,时间只能为3、6、9、12这四种整点数,再给出9种拨动钟表的方案,每次每面钟最多能顺时针拨动90度,即由3->6,6->9,9->12,12->3。问最少使用几种方案,就可使所有的钟表都拨到12点!若使用拨动方案数相同,则输出字典序最小的方案。
9面钟编号:
A B C
D E F
G H I
移动方案:
1 ABDE
2 ABC
3 BCEF
4 ADG
5 BDEFH
6 CFI
7 DEGH
8 GHI
9 EFHI
首先我思考的是搜索,求最优,如何保存状态呢?状态压缩,可以看出:每种方案最多使用0~3次(因为使用4次就相当于没有使用),所以最多的状态为4^9=26144,经过编码,完全可以保存下来,而且搜索的时间复杂度应该不算太高!当然如果使用dfs,完全无视空间的状态存储(基本不会栈溢出了)!只需要考虑一下适当的剪枝,进行优化即可!
这里再来说说非搜索的思路:
(1)所有的钟面只有4种状态(3,6,9,12),对就可转化为(1,2,3,0)
(2)所有的方案只能拨动某些钟面到下一个状态,如方案1可拨动A、B、D、E,其它的不能拨动,我们可以把它扩展记为1 1 0 1 1 0 0 0 0,表示对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
这样可以看出这个表(记录A[i][j])中的每列都是控制一面钟,若假定每种方案的使用次数为b[i],每面钟的初始状态为c[i],这样就可以计算出每面钟最少需要拨动几次就能达到目标状态,修改c[i]的值为最少拨动的次数。这样我们就可以建立以下的方程:
sum(A[i][j]*b[i])%4=c[j](其中b[i]表示第i种方案使用的次数,且0≤b[i]≤3)
写成一般方程组形式为:Ab=c -->b=A-1c,(其中:A为方程的系数矩阵,A-1为矩阵的逆)
这样我只要求出矩阵A的逆,即可计算出b[i]的值。由数论的知识可知通过初等行变换,可以把A|E-->E|A-1,注意在求逆的过程中,要加遇负转正,且要模4的处理,最终计算得A-1为:
3 3 3 3 3 2 3 2 0
2 3 2 3 2 3 1 0 1
3 3 3 2 3 3 0 2 3
2 3 1 3 2 0 2 3 1
2 3 2 3 1 3 2 3 2
1 3 2 0 2 3 1 3 2
3 2 0 3 3 2 3 3 3
1 0 1 3 2 3 2 3 2
0 2 3 2 3 3 3 3 3
至此,我们就可以通过二重循环以求得每个b[i]的值,即:
b[i]=sum(A-1[i][j]*c[j])%4
最后按要求输出这些b[i]的值即可。