题目:http://www.nocow.cn/index.php/Translate:USACO/fence
看完这道题目的第一想法就是,遍历所有的边,而且每一条边的经过次数只能一次。是离散数学里面的图论的欧拉通路问题,在这里充分体现了数学的重要性。
定理:无向图G有欧拉通路的充分必要条件是G为连通图,并且G仅有两个奇度结点或者无奇度结点。
(1)当G是仅有两个奇度结点的连通图时,G的欧拉通路必以此两个结点为端点。
(2)当G是无奇度结点的连通图时,G必有欧拉回路。
因此第一个点,要么是最小的度数为奇数的点(如果存在),否则为是下标最小的点。
我的想法是采用深度遍历的回溯方法,如果不能一次遍历完所有的边,则回退到上一个节点,直到搜索到结果为止,代码如下:
可惜的是,时间一直都是超时的,通不过去。
看了USACO的提示,他也是采用深度遍历的方法,然后将结果逆序保存打印。但是这个深度遍历跟我的那个方法有着本质的区别,他的深度遍历是遍历边,而我的深度遍历是深度搜索,时间复杂度不在一个数量级上。很让我奇怪的是,为什么简简单单的一次深度遍历边,然后逆序保存节点就可以找出欧拉通路呢?
举个例子:
正确的欧拉通路顺序是红色的,但是按节点下标的深度遍历的顺序是蓝色方式。很显然如果从方向来看的话,二者的结果肯定是不同的。
我们先看一下代码入下:
按照程序的执行思路跑一遍,可以得到如下步骤:
find(1):
map[1][2] = 1;
find(2)
map[2][3] = 1;
find(3)
map[3][4]=1;
find(4)
map[4][2]=1;
find(2) //此时所有的map[2][i] = 0
记录2
return;
所有map[4][i]=0
记录4
return
map[3][i] =0
记录3
return;
所有map[2][i]=0
记录2
return
map[1][5] = 1;
find(5)
map[5][6] = 1
find(6)
map[6][1] = 1;
find(1);
ALL map[1][i]=0;
记录1
return
记录6
return
记录5
return
记录1
return;
逆序打印结果是1 5 6 1 2 3 4 2,就是正确答案。
本来我也想不明白其中的缘由,但是如果把问题理解为实际上我们就是寻找一个点序列,使得按照这个点序列遍历边,能经过每一条边,并且只有一次。根据欧拉通路的从要条件,我们可以很明确的得到第一个点(起点)S。那么我们要确定的是下一个欧拉通路的点P,是与起点连接的点中的哪一个?那我们可以想一下,哪一个点是下一个欧拉点P呢?就是沿着S P然后经过深度遍历,能够将所有的边都遍历到的点就是欧拉点,就是经过SP往下深度遍历以后,所有MAP【i】【j】=0。
运行结果如下: