【算法竞赛萌新首个题解,欢迎各位大神指导】
咳咳咳,第一次,找了一道有意思的搜索题目,算法嘛,就是普通的深搜(dfs),迭代加深(id);
对于算法初学者,搜索是必备的技能了,搜索中最常见的问题,不过一个表格,或者是一个地图,或者是个迷宫,问能否走到终点或者是最少需要多少步(看上去和本题比较像)。但有的时候会有比较不一样的题目,比如三维啊,马走日(跟这个题有微妙的关系)象走田啊,之类之类的,便不在此赘述了;
考虑到有和我一样的萌新宝宝,在下详细谈谈对于迭代加深(Iterative Deepening)的思考和理解;首先是引用一段死知识点,大家尽量看懂:
http://blog.csdn.net/alan_lon_/article/details/79392948
这是我为这道题引来的知识点;大家应该能(应该能!应该能!)看懂,不过要是真没看懂的话,也没关系,我可是很耐心的;
一言以蔽之,迭代加深就是在我们能预估搜索层数较少的时候,避免逐枝搜索造成深层搜索对时间的浪费。方法就是逐层扩展,一层一层从浅到深作深搜,直到搜到目标节点!
好进入正题,我从洛谷把这道题扒下来:
第一行有一个正整数T(T<=10),表示一共有N组数据。接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑士,*表示空位。两组数据之间没有空行。
输出格式:对于每组数据都输出一行。如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出-1。
样例输入
2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100
样例输出
7
-1
解析:
这道题就是说,有一个残局棋盘,二十四个骑士(骑士就是中国象棋的马),黑白各一半,要求最后在十五步之内尽量快的把二十四个骑士弄成左下右上各十二,超过了十五步就输出-1;
这时我一拍桌子!喝!这不就是迭代加深么,多么明显的“暗示”呵。(对不起~在下失态了)
于是我三下五除二写下了深搜,迭代加深,但是我意识到一个很严重的问题,迭代加深了半天,该错还是错,我天,这时什么操作,我明明已经击中他的要害了啊;
然后我参照了题解,才明白的(本人智商极低,那题解太简单我看不懂,看了半天才稍微明白了点,所以我立志要写天下最好懂的题解),原来,这一步搜下来,按照遍历的态度肯定就又搜回去了,搜回去,搜过来,搜回去,搜过来,这不就完了么;
所以,遍历八个方向的顺序就尤为重要了,避免搜回去加一组特判,完美解决啊;
嗯省选题就是省选题,不简单的,果不其然没法写;为甚么呢,因为想的太简单了,搜索之外的主函数太过暴力。(其实搜索写的也蛮乱的,就算主函数写对了也过不了)于是又打开详细题解看,呃呃呃,我明白了,原来搜索的分类讨论很乱,主函数调用搜索函数也不得当;
因为残局和目标棋局肯定有所不同,有多少不同?能否量化?不能确切说,但是肯定有个下限。到底有多少个位置残局和目标局是不同的,那就说明最少走多少步可能把残局复原;
于是乎,我们就从这个数开始搜,搜到十六步(超过15的第一个整数);那么这道题就可以完美解决了;
好,上面说的都是大概思路,咱现在唠一唠搜索的细节,与其他搜索不同的是,这个走棋的搜索,可以分为四种情况,好,现在为大家引用几句大神的题解;
1,原来骑士归位了,改完没归位(当然需要把差异度加一)
2,原来骑士没归位,改完归位了(当然就要把差异度减一)
3,原来空位没归位,改完归位了(同1)
4,原来空位归位了,改完没归位(同2)
没听懂吗?没关系,下面附的题解代码,有我逐句的详细解释,一定让你看懂(再看不懂。。。那你。。。再看一遍);
好,清楚了,下面我解释一下异或的过程,因为我们移动的不是棋子而是空格,所以只要用个交换就可以了(个人认为swap()函数都能办到)但是看写异或的人还是蛮多的;如果-1和1异或,你会发现电脑算出来的是-2,然后1和-2异或出来的是-1,最后-2,和-1异或出来的是1,结果就是把-1,和1交换了;
如果是-1和0异或,那就更简单了吧,这里就不解释了,留给大家脑补;
好这道题讲到这里就结束了,如果各位大神认为哪里讲的不够清楚,可以在下面提意见或者是挑错误;
Thanks!