(写在前面:这个东西可能很早之前就有了,不过我是蓝桥杯博弈题刷多了,自己总结出来了,所以记录一下吧)
一、从上到下dfs的不足和解决方案
在看模板之前,我们先来看一下传统的从上到下的dfs (深度优先遍历)有什么不足,来看一个最简单的 Fabonacii数列:Fn=Fn-1+Fn-2。看下下面的递归代码:
private static int f(int i)
{
if(i==1||i==2)
return 1;
return f(i-1)+f(i-2);
}
上面这一段递归代码,简单明了,一看就懂。可是效率真的不敢恭维,为什么呢,上一张图解释一下
如上图所示,比如我们要计算f5,那么就得计算 f4和f3,在计算f4的时候,算了一遍f3,然后算完f4, 还得算一遍f3
当n很小的时候,时间方面是hold得住的,比如就简单一个f5,而当n稍微大一点,求个f40就慢得不行了!
更不用说求f1000那样的大数了。
那么我们应该如何减少时间?提高效率?
一种方法是不要采用从顶到下,而是从下到上,这样就可以减少大量的时间
当然这种逆流而上的方法对于求解这道题是很好的,但是这种方法和后面要讨论的博弈题的解题模板没有太多关系,故不涉及太多。事实上, 从下到上需要确定每一个递归出口,在博弈题中通常不那么好确定每一个递归出口;而且从下到上这种思维与博弈的过程是逆向的,理解起来可能会费力。
那么现在问题就变成了,还是从顶到下,我们要怎么减少时间?提高效率?
费时是因为我们一直在做重复工作,我们算了太多遍的f3,说白了,它算了一遍的f3,没有把它保存起来,等到下次用到又得重新算一遍。那我们就这样,它算出一遍f3,就找个本子把它抄下来,f3=2, 这样下次再需要f3,就先看看本子里面有没有f3,没有再算。这样就把重复计算浪费的时间换成在本子上查找的时间。一般来说查找时间都会远远小于重复计算的时间,所以可以缩短时间。
上面说的所有浓缩成几个字:有记忆的dfs
二、有记忆的dfs应用到博弈题
我们知道博弈题一般输入都是一个局面,输出是必胜局,必败局还是平局
那么如何用dfs来解决博弈题目呢
我们知道一个局面和另一个局面之间都是一步,那么我们可以通过所有的下一个可能局面来推出当前局面是必胜还是其他