欧拉回路让我甚是苦恼, 估计是这两天玩游戏浮躁了自己, 在理解算法的时候就没认真。 没有完全理解就上战场了, 结果各种RE+WA。下面是我对欧拉回路的理解。
1.基本概念: 欧拉道路 与 欧拉回路(区别在于一个‘回’字, 不再诉述, 自己搜索)
2.判断方法: 图是否连通(用并查集实现)+ 点的度数是否满足条件(全为偶数, 或只有两个奇数)
3.输出路径: 用一个DFS压栈, 然后从栈中输出。(不甚理解, 如果你也是, 欢迎讨论)
4.记录边关系:邻接矩阵G[MAX_V][MAX_V]用来表示密集的边edge关系, 无向图中 矩阵G是对称的, 要G[u][v]与G[v] [u]同步更新。有向图相反。 如果是稀疏的边关系, 结点vertex又非常的多, 开一个G[MAX_V][MAX_V], 显然是不合理的,用G[MAX_V]来表示,这个数组的元素是指针(实际是链表), 链表中的每一个结点, 指向与u有edge关系的vertex。
5.DFS中标记访问: 经常是用一个vis[MAX_V][MAX_V]来表示, 同G矩阵很像。 但其实 有时候G可以这样用: G[u][v]的数值表示u与v之 间路的条数(而非简单的1, 表示存在关系), 每走过一遍, G[u][v]--; 当G[u][v]为零时, 也就相当于vis[u][v] = VISTED;
6.欧拉回路的疑问: a.DFS搜索树应该存在着走不通的路啊, 这样的路难道不是非法的吗? 就不用加判定条件吗? 这个问题我至今似懂非懂。 最下面有两个段代码, 这一比较, 各种不理解。
7.题目:uva10596:简单基础题, 注意vertex数目小于2的情况。再有, 我WA + RE了好多次。
uva10054:据说这题判回都不用, 只要判度数符合就行。 但我还是用并查集判回了, 结果在计算集合数目的时候, 把没有的 点也考虑进来了。 如果不懂我说的意思, 你把题中样例二 的 3 跟 4 分别用 7 8代替试试。
uva10129:有向图的欧拉道路存在性判断。
8.还需要做的:
a. DFS路径这边还是不理解, 需要再去理解。 这点很重要, 只有理解透彻了, 才能根据题目改造算法。
b. 目前做过的题目基本比较水, 虽然我WA了很多遍, 但我相信这是自己状态不好(小错误不断)再加算法理解得不透彻引起 的。需要做些更深点题目 , 无向-》有向-》混合。 做些助于更好理解欧拉的题目。
我看了别人的算法后写的, 其中E是终点, 在main里指定。
bool DFS(int root)
{
if (countE == E && root == end) { //访问边数等于总边数 并且 现在的点为终点时
return true;
}else if (countE == V && root != end) {
return false;
}
for (int i = 0; i < V; i++) {
if (G[root][i] && !vis[root][i]) {
vis[root][i] = vis[i][root] = 1;
countE++;
if (DFS(i)) { //如果递归下去能找到终点则打印, 否则回溯
printf("%d->", i);
return true;
}else {
vis[i][root] = vis[root][i] = 0;
countE--;
}
}
}
return false; //当此点root(未到达终点)没有其它点与之有关系 或 其它连接的边已经走过时
}
这是刘汝佳书上的:
void euler(int u){
for(int v=0; v<MAXN; ++v) if(G[u][v]){
vis[u][v] = vis[v][u] = 1;
euler(v);
printf("%d %d\n", u,v);
}
}
9. 后期心得: a.用DFS判断连通:无论图是有向无向, 都把图当做无向。 这点很重要,不然DFS无法从任意点搜索起。
b.在判断点是否有过属性改变前, 要先判断, 这一点是否原本就有。 如果原本就有才有属性改变可言, 否则何必去判断呢?况且还可能会引起BUG 比如:
//judge
bool okDFS()
{
for (int v = 0; v < MAX_V; v++) {
if (vis[v] == UNVISTED) {
return false;
}
}
return true;
}
for扫描所有的点(有的点是不存在的, 比如样例只有a d f e这四个点其余点都不存在),这时候你去判
断vis属性是否全变为“已访问” , 是不合理的。 当然啦 , vis一般会先全部清零。 但如果是别的属
性呢?