书山有径勤为路>>>>>>>>

<<<<<<<<学海无涯苦作舟!

感悟DFS

昨天看到了一句话让我对DFS算法有极深的感悟。

这句话就是:DFS有三个条件:1.最深深度 2.结束条件 3.如何扩展。

其实对于1, 2,两点,感觉不是问题的关键,第三点

才是问题的核心。如何说呢?还是来结合一个实例吧,不然,

很难说清楚。

例题:

有三个容量分别是A,B,C升的桶,A,B,C分别是三个从1到20的整数,

最初,A和B桶都是空的,而C桶是装满牛奶的。

有时,约翰把牛奶从一个桶倒到另一个桶中,直到被灌桶装满或原桶空了。

当然每一次灌注都是完全的。由于节约,牛奶不会有丢失。

写一个程序去帮助约翰找出当A桶是空的时候,C桶中牛奶所剩量的所有可能性。


解题思路:

每次最多无非有6种倒法,即a->b;a->c;b->a;b->c;c->a;c->b。

所以如果用a、b、c代表三个桶的容积,x、y、z代表当前三个桶内的牛奶数,

那么不难算出执行完a->b后,x变为max(0,x+y-b),y变为min(b,x+y),z不变。

其它倒法类似。


说到这里,思路也就出来了。什么时候a->b,什么时候a->c……

这个就是递归的方向的控制了。这个也是相当重要的,因为,

这个是扩展的第一步,如果这一点解决不了,那么就没有后话了。

其实这一点是很好控制的,只要a>0, b不满,就可以实现a->b了。

其它的6个倒法也是一样的。

有了扩展的方向以后,递归就完成50%,另外的一半就是,在每

个方向上的具体的参数变化了,比如本题的x变为max(0, x+y-b),

y变为min(b, x+y), z不变……,有个这两点之后,那么DFS的

核心内容也就完成了,一不小心,你就会AC了。


下面给出核心的代码。

     if(a>0 && b<B)  //A向B倒, c不变
		DFS(max(0, a+b-B), min(B, a+b), c);
	if(a>0 && c<C)  //A向C倒,b不变
		DFS(max(0, a+c-C), b, min(C, a+c));
	if(b>0 && a<A)  //B向A倒,c不变
		DFS(min(A, a+b), max(0, b+a-A), c);
	if(b>0 && c<C)  //B向C倒,a不变
		DFS(a, max(0, b+c-C), min(C, b+c));
	if(c>0 && a<A)  //C向A倒,b不变
		DFS(min(A, a+c), b, max(0, a+c-A));
	if(c>0 && b<B)  //C向B倒,a不变
		DFS(a, min(B, b+c), max(0, b+c-B));
6个if语句就是控制方向的。
DFS中的max, min就是用来控制参数的变化的。

总结一下,其实我一直在强调“如何扩展”这个方面。
这个方面又分为两个细节:
1.扩展方向
2.参数变化

思考一个DFS题目,要着重在这两个细节考虑。

posted on 2011-10-17 09:33  More study needed.  阅读(355)  评论(0编辑  收藏  举报

导航

书山有径勤为路>>>>>>>>

<<<<<<<<学海无涯苦作舟!