[问题] UVa 11007 魔术方块 最少步骤解

楼主: nicknick0630 (NICK)   2019-05-21 00:09:53
UVa 连结 : https://reurl.cc/8OKXo
题目简易说明
这题是要解一个 2x2x2 的二阶魔术方块 ( 6 面、6 颜色 )
会给定一个魔术方块的状态
然后要找出可以还原魔术方块的最少步骤是多少
输入面的顺序为 : Top , Front, Right , Bottom, Back , Left
且每面的初始色 : White, Red , Yellow, Blue , Orange, Green
我的解法一
参考维基百科 : https://reurl.cc/Ea3Qn
二阶魔方最有只有 3674160 种状态
而且最多只要 14 个步骤就能将方块还原
以下是需要转动步骤的状态数:
所需步骤 状态数量
0 1
1 6
2 27
3 120
4 534
5 2256
6 8969
7 33058
8 870072
9 360508
10 930508
11 1350852
12 782536
13 90280
14 276
所以我就将这 3674160 利用 BFS 由上到下暴力列举出来
列举方法:
以 Front、Right、Bottom 三面相交的那块方块为基准点
可以做的转动只有 6 种 : U Up L Lp B Bp
U : Top 那面面对自己做 顺 时针旋转
Up : Top 那面面对自己做 逆 时针旋转
L : Left 那面
B : Back 那面
就从步骤 0 开始 ( 方块还原状态 )
依序做 6 种转动,并得到步骤 1 的方块状态
直到步骤 14
其中可以用一些规则去避免重复 ( 不然 6^14 = 7百多亿 )
1. L L L = Lp ( 转 270度 = 转 -90度 )
2. 若上一步骤是 L,则这一步骤就不能为 Lp ( 做白工 )
3. L L = Lp Lp ( 我选择遇到 Lp Lp 就不要做 )
但是除了以上三种,还是会有很多重复是抓不到的
所以我将每种状态放入 Hash Table 中
( C++ unordered_multimap )
key : 根据方块的状态 (每一面颜色) 所 "乱凑" 出来的数值
value : 该方块的资讯 (状态、还原所需步骤等等)
每新算出一种状态 ( 不违反上面 3 个规则 )
还要去 Hash Table 中检查有没有重复,没有的话就同样丢入 Table 中
最后
只要把题目输入的方块状态同样依据上面算 key 的方法算出来
再去 Hash Table 找,并得到该方块的资讯,就可以知道最短步骤
缺点
这样太慢,UVa 时限是 3 秒,我光是跑完列举就要大概 10 秒了
其中大部分的时间都是花在 Hash Table 查找
( 因为 hash 会碰撞,所以只能用 equal_range(key) 去查找,但还是剖慢)
我的解法二
为了避免掉 Hash Table 查找
所以直接对题目给的方块状态去做暴力 BFS
不过这次就不使用 Hash Table 来储存找到的状态
也不检查除了上面 3 个规则以外是否还有重复的
这样会比较快
但是因为数量增长太大,也是会很慢而且内存还会爆掉
问题
请问各位大大有没有什么更快的做法呢?
UVa 上的数据很多人都可以在 1 秒内 AC,但我一职 TLE ...
或是我还有哪里可以再加快的呢?
谢谢
附上写得不好的程式码 ( 解法一 )
https://pastebin.com/embed_iframe/c2e3idba
作者: achicn3 (Sher)   2019-05-21 01:55:00
可以问杨老师 XD
作者: FRAXIS (喔喔)   2019-05-21 11:58:00
不能把 3674160 个状态找个 encoding 法 + perfect hash?而且你真的需要 unordered_multimap 吗?
作者: fatcat8127 (胖胖猫)   2019-05-21 13:35:00
双向BFS吗?
楼主: nicknick0630 (NICK)   2019-05-21 16:03:00
回 F 大 :当然如果可以找到perfect hash 应该就可以解决问题了,只是这样hash的方法的我真的设计不出来啊QQ回 fatcat 大:我有试过,不过同样也要去检查有没有规则外的重复状态,所以还是有一样的问题
作者: cutekid (可爱小孩子)   2019-05-21 17:48:00
https://github.com/MeepMoop/py222 ←不知道有帮助吗
作者: FRAXIS (喔喔)   2019-05-21 21:10:00
应该不用设计吧 因为状态数是固定的 只要随机试几个自然就会找的到 perfect hash?https://en.wikipedia.org/wiki/Perfect_hash_function
作者: firejox (Tangent)   2019-05-21 21:22:00
IDDFS ?
作者: oToToT (屁孩)   2019-05-21 22:10:00
从解状态跟待解状态两边同时开始BFS/IDDFS会较佳,至少上礼拜某个比赛这样会过@@
作者: firejox (Tangent)   2019-05-21 23:03:00
如果担心内存爆掉 就把资料压在72个bit就好或许可以用A*,大概是计算顶点的曼哈顿距离之类的
作者: idiont (supertroller)   2019-05-21 23:30:00
双向BFS可以过 刚刚测试过了 跑了0.720秒6^24 < 2^63 所以可以靠long long存就好了 而且不会碰撞一格有6种情况 24格就6^24种情况 不过实际上大部分都不存在就是了然后一个方块会有24种摆放方式 我是每种都算出他的hash值取最小的

Links booklink

Contact Us: admin [ a t ] ucptt.com