2017年第八届蓝桥杯 - 省赛 - C/C++大学A组 - C. 魔方状态
二阶魔方就是只有2层的魔方,只由8个小块组成。
小明很淘气,他只喜欢3种颜色,所有把家里的二阶魔方重新涂了颜色,如下:
前面:橙色 右面:绿色 上面:黄色 左面:绿色 下面:橙色 后面:黄色
请你计算一下,这样的魔方被打乱后,一共有多少种不同的状态。
如果两个状态经过魔方的整体旋转后,各个面的颜色都一致,则认为是同一状态。
请提交表示状态数的整数,不要填写任何多余内容或说明文字。
Ideas这道题相对来说比较麻烦,而且比赛的时候放在第三题,有点恐怖,建议如果比赛的时候遇到这种填空题,20分钟解决不出来就跳过吧。
如果想要解决这道题,首先面临的第一个问题就是,魔方是三维,我们怎么用计算机语言进行表示。
二阶魔方是由八个块组成的,我们先给这8个块进行编号,上面四个块编号为03,下面四个块编号为47。
然后对于每一个块,都有六个面,其中有三个面是有颜色,另外三个面在魔方内部,是看不见的,所以我们还要对每一个面进行编号。
编号为0的块,它的6个面可以表示为['o', 'y', 'x', 'x', 'g', 'x'],其中o表示橙色,y表示黄色,g表示绿色,x表示看不见。
接下来我们就可以用一个二维字符数组表示一个二阶魔方:
cube = [['o', 'y', 'x', 'x', 'g', 'x'], ['o', 'y', 'g', 'x', 'x', 'x'], ['x', 'y', 'g', 'x', 'x', 'y'], ['x', 'y', 'x', 'x', 'g', 'y'], ['o', 'x', 'x', 'o', 'g', 'x'], ['o', 'x', 'g', 'o', 'x', 'x'], ['x', 'x', 'g', 'o', 'x', 'y'], ['x', 'x', 'x', 'o', 'g', 'y']]
魔方的状态表示完了之后,接下来就要转动,进行状态转移。
玩过魔方的应该都知道,它的状态转移其实只需要通过三种旋转就可以达到:上面旋转(U)、右面旋转(R)、前面旋转(F)。
假如对于上面旋转(U)操作,首先0、1、2、3四个块的位置要交换。
0 -> 3 3 -> 2 2 -> 1 1 -> 0
然后每个块的6个面编码也要变换:
0 -> 4 4 -> 5 5 -> 2 2 -> 0
同理我们可以得出剩下两种旋转对应的块和面的变换,这样我们就得到了魔方状态转移的步骤。
接下来我们就要进行搜索了,得到魔方的所有状态。
对于某一种状态,它有R、U、F三种操作,通过每一种操作可以得到一个新的状态,而对于每一种状态,要判断一下之前有没有出现过,如果没有,添加到状态集合中,并且后面要基于这种状态继续搜索。
所以这类似于一个BFS的问题,我们需要通过队列来辅助实现。
另外题目中说“如果两个状态经过魔方的整体旋转后,各个面的颜色都一致,则认为是同一状态”,其实就是我们进行去重的依据,还需要定义一个辅助函数进行魔方的整体旋转。
定义函数try_add,传入一个魔方的状态,然后进行整体旋转操作,同样类似于面的旋转操作,不同的是三个面都要进行整体旋转。
Code Pythonfrom collections import deque from copy import deepcopy def process_cube(state) -> str: return ''.join([''.join(x) for x in state]) def u(state): # 上面顺时针旋转一次 def u_cell(cell): # 上面顺时针旋转一次对应的每个块的面编码变化 cell[4], cell[5], cell[2], cell[0] = cell[0], cell[4], cell[5], cell[2] for i in [0, 1, 2, 3]: u_cell(state[i]) state[0], state[1], state[2], state[3] = state[1], state[2], state[3], state[0] return state def r(state): # 右面顺时针旋转一次 def r_cell(cell): # 右面顺时针旋转一次对应的每个块的面编码变化 cell[0], cell[1], cell[5], cell[3] = cell[3], cell[0], cell[1], cell[5] for i in [1, 2, 5, 6]: r_cell(state[i]) state[1], state[2], state[5], state[6] = state[5], state[1], state[6], state[2] return state def f(state): # 前面顺时针旋转一次 def f_cell(cell): # 前面顺时针旋转一次对应的每个块的面编码变化 cell[1], cell[2], cell[3], cell[4] = cell[4], cell[1], cell[2], cell[3] for i in [0, 1, 4, 5]: f_cell(state[i]) state[0], state[1], state[4], state[5] = state[4], state[0], state[5], state[1] return state def u_whole(state): # 上+下面顺时针旋转一次 def u_d_cell(cell): # 上+下面顺时针旋转一次对应的每个块的面编码变化 cell[4], cell[5], cell[2], cell[0] = cell[0], cell[4], cell[5], cell[2] for i in range(8): u_d_cell(state[i]) state[0], state[1], state[2], state[3] = state[1], state[2], state[3], state[0] state[4], state[5], state[6], state[7] = state[5], state[6], state[7], state[4] return state def r_whole(state): # 右+左面顺时针旋转一次 def r_l_cell(cell): # 右+左面顺时针旋转一次对应的每个块的面编码变化 cell[0], cell[1], cell[5], cell[3] = cell[3], cell[0], cell[1], cell[5] for i in range(8): r_l_cell(state[i]) state[1], state[2], state[5], state[6] = state[5], state[1], state[6], state[2] state[0], state[3], state[4], state[7] = state[4], state[0], state[7], state[3] return state def f_whole(state): # 前+后面顺时针旋转一次 def f_b_cell(cell): # 前+后面顺时针旋转一次对应的每个块的面编码变化 cell[1], cell[2], cell[3], cell[4] = cell[4], cell[1], cell[2], cell[3] for i in range(8): f_b_cell(state[i]) state[0], state[1], state[4], state[5] = state[4], state[0], state[5], state[1] state[3], state[2], state[7], state[6] = state[7], state[3], state[6], state[2] return state def try_add(state): for _ in range(4): state = u_whole(deepcopy(state)) for _ in range(4): state = r_whole(deepcopy(state)) for _ in range(4): state = f_whole(deepcopy(state)) if process_cube(state) in states: return states.add(process_cube(state)) queue.append(state) if __name__ == '__main__': cube = [['o', 'y', 'x', 'x', 'g', 'x'], ['o', 'y', 'g', 'x', 'x', 'x'], ['x', 'y', 'g', 'x', 'x', 'y'], ['x', 'y', 'x', 'x', 'g', 'y'], ['o', 'x', 'x', 'o', 'g', 'x'], ['o', 'x', 'g', 'o', 'x', 'x'], ['x', 'x', 'g', 'o', 'x', 'y'], ['x', 'x', 'x', 'o', 'g', 'y']] queue, states = deque(), set() queue.append(cube) states.add(process_cube(cube)) while queue: front = queue.popleft() u_state = u(deepcopy(front)) try_add(u_state) r_state = r(deepcopy(front)) try_add(r_state) f_state = f(deepcopy(front)) try_add(f_state) print(len(states))Answer: 229878