IDA*、操作打表、并行处理-The Rotation Game HDU - 1667
万恶之源
优秀题解
用文字终究难以穷尽代码的思想
思路
每次操作都有八种选择,相当于一棵每次延申八个子节点的搜索树,故搜索应该是一种方法。而这题要求求最少步数,我们就可以想到可以试试迭代加深搜索(但其实我做它因为它是书本的习题)。再搭配一个估值函数来剪枝就很香啦。
轮换方块(操作打表)
我的原始思路十分粗暴,就是用一个二维数组来存储这个“#”图形,但是这会十分浪费空间,在写轮换操作时的代码时也很繁冗。
我学到的呢,是用一维数组来存储这个图形,也就是直接用题目的输入生成一个数组。这样进行轮换操作可能不如二维的直观,但熟悉熟悉就好吧。所以应该如何轮换呢?这其实相当于一个映射,由于每个元素在原来的图形的位置是独特的,那将原图形一维化之后,这个元素的位置也仍然是独特的。因此,我们只需要找出,原来“#”图形的某一列/行在一维数组的对应坐标就好。
但是由于数据规模不大,我们可以打表来实现,也就是事先找出某个操作需要使用的坐标。
const int index[8][7] = { //从A-H操作变动的下标
{ 0,2,6,11,15,20,22 }, //A
{ 1,3,8,12,17,21,23 }, //B
{ 10,9,8,7,6,5,4 }, //C
{ 19,18,17,16,15,14,13 }, //D
{ 23,21,17,12,8,3,1 }, //E
{ 22,20,15,11,6,2,0 }, //F
{ 13,14,15,16,17,18,19 }, //G
{ 4,5,6,7,8,9,10 }, //H
};
可行性剪枝(估值函数)
再做这题之前我做了另外一题,HDU - 1560 - DNA sequence,这题估计的是剩余还需要处理的长度,本题估计的则是剩余还需要处理的方格(冥冥之中总感觉有相似之处)。
估计方格
因为每次轮换,最多只会引进一个目标元素(直观感受),因此,还需要处理的方格(即上文需要估计的量),就等于中心元素中,不为目标元素的元素的个数,也就是非目标元素的个数。一旦目标元素确定那计数就小菜一碟啦,但是我们怎么知道我们的目标是什么?
目标元素
我的原始思路是,开局在中心元素个数最多的即我们的目标,但是想了想说不定人家也可能一手好牌打得稀烂(结果确实存在这种情况,开始在中间最多的并不是正解),于是我最后决定还是得枚举目标,但是我总感觉开始在中间最多的越有可能是正确答案,于是按照出现的次数排序来进行枚举,搜索。(但事实证明这并没有必要,而且写出来的效果就很让人怀疑,一个问题居然要搜索三次)
做完之后我参考了一下其它题解,发现了一种更好的思路。我们完全可以作一棵没有目标的墙头草,谁最多我们就往哪倒。也就是说,我们可以计算在中间1,2,3这三个元素的个数的最大值,一旦这个计算结果等于8,我们就完成了任务!这时再去检查是谁达到了这个数字即可。(另外这样能够保证我们的结果就是最优解,按我的原始思路,很有可能出现三组解(一个搜索一个解),还需要对这三组解进行进一步的比较)
重大问题
- cnt()函数——估计哪个数字应该优先搜索。
在排序时思路不对,导致三个数字不能正常被排序与标记。
(我有时觉得这个函数没有用,事实上确实没有用,还徒增很多烦恼)
- 搜索时忘了有H这一操作。。。甚至在很后面才发现。。。
打印出每次的操作,发现只有7种操作,那就可以发现这个bug了,或者是分析出错的样例,然后分析为什么没有出现某个路径,然后再定位到拓展叶子节点的代码,应该可以发现这个bug
- 没有仔细审题 || 没有考虑特殊情况——No moves needed
If no moves are needed, output "No moves needed",为什么说它严重呢,因为这将导致对拍完全没有问题,但是交上去就是WA。-__-
以后做题一定要特例先行!
- 没有意识到1, 2, 3都有可能成为最后的答案,即使某一个数在中心的个数最少。
这个其实反而是最开始的想法,但做着做着题就认为中间数量最多的就是最后答案。。。还是考虑的不够全面啊
- 最后的判断依据
接着第四点,由于任何一个数都有可能成为答案,最后的判断依据应该是在某个深度下,谁的操作路径字典序最小。并且,这里面还要考虑到如果一个路径不存在,它的长度可能是最小的(string,长度为0)判断完之后,最后还得输出中心元素,这两个操作如何协调,也是一个麻烦的问题。
- 尝试用map储存状态
这会导致TLE==,感觉可能是状态太多了,希望以后的自己能对这个问题有更多理解,最好还能提出解决的办法。
- 代码十分冗杂,同时时间开销非常大,一定要学习优秀的代码
我的思路从一开始就不太正确,以至于后面花费了相当多的精力去给它修修补补。导致了这种情况的发生。
一点感悟
方向错误也不是第一次了,每当出现这种情况,我就会想起托勒密,他穷尽他的心血将地心说完善得几乎完美,但终究在一开始他便错了。但是他的错误也给后人带来的启示与借鉴,我也希望我的每一次错误都能够给日后的我或看到这篇文章的人们提供一种信息,某条路是不行的,帮助他们少走弯路,以上。