hiho欧拉路·二

分析:

小Ho:这种简单的谜题就交给我吧!

小Hi:真的没问题么?

<10分钟过去>

小Ho:啊啊啊啊啊!搞不定啊!!!骨牌数量一多就乱了。

小Hi:哎,我就知道你会遇到问题。

小Ho:小Hi快来帮帮我!

小Hi:好了,好了。让我们一起来解决这个问题。

<小Hi思考了一下>

小Hi:原来是这样。。。小Ho你仔细观察这个例子:

因为相连的两个数字总是相同的,不妨我们只写一次,那么这个例子可以写成:3-2-4-3-5-1。6个数字刚好有5个间隙,每个间隙两边的数字由恰好对应了一块骨牌。

如果我们将每一个数字看作一个点,每一块骨牌看作一条边。你觉得是怎么样的呢?

小Ho:以这个例子来说的话,就是:

要把所有的骨牌连起来,也就是把所有的边都走一次。咦,这不是欧拉路问题么!

小Hi:没错,这问题其实就是一个欧拉路的问题,不过和上一次不一样的在于,这一次我们要找出一条欧拉路径。

小Ho:那我们应该如何来找一条路径呢?

小Hi:我们还是借用一下上次的例子吧

使用我们上一次证明欧拉路判定的方法,我们在这个例子中找到了2条路径:

L1: 4-5-2-3-6-5
L2: 2-4-1-2

假设我们栈S,记录我们每一次查找路径时的结点顺序。当我们找到L1时,栈S内的情况为:

S: 4 5 2 3 6 5 [Top]

此时我们一步一步出栈并将这些边删除。当我们到节点2时,我们发现节点2刚好是L1与L2的公共节点。并且L2满足走过其他边之后回到了节点2。如果我们在这个地方将L2先走一遍,再继续走L1不就刚好走过了所有边么。

而且在上一次的证明中我们知道,除了L1之外,其他的路径L2、L3...一定都满足起点与终点为同一个点。所以从任意一个公共节点出发一定有一条路径回到这个节点。

由此我们得到了一个算法:

  1. 在原图中找一个L1路径

  2. 从L1的终点往回回溯,依次将每个点出栈。并检查当前点是否还有其他没有经过的边。若存在则以当前点为起点,查找L2,并对L2的节点同样用栈记录重复该算法。

  3. 当L1中的点全部出栈后,算法结束。

在这里我们再来一个有3层的例子:

在这个例子中:

L1: 1-2-6-5-1
L2: 2-3-7-2
L3: 3-4-8-3

第一步时我们将L1压入栈S,同时我们用一个数组Path来记录我们出栈的顺序:

S: [1 2 6 5 1]
Path:

然后出栈到节点2时我们发现了2有其他路径,于是我们把2的另一条路径加入:

S: 1 [2 3 7 2]
Path: 1 5 6

此时L2已经走完,然后再开始弹出元素,直到我们发现3有其他路径,同样压入栈:

S: 1 2 [3 4 8 3]
Path: 1 5 6 2 7

之后依次弹出剩下的元素:

S:
Path: 1 5 6 2 7 3 8 4 3 2 1

此时的Path就正好是我们需要的欧拉路径。

小Ho:原来这样就能求出欧拉路,真是挺巧妙的。

小Hi:而且这个算法在实现时也有很巧妙的方法。因为DFS本身就是一个入栈出栈的过程,所以我们直接利用DFS的性质来实现栈,其伪代码如下:

DFS(u):
While (u存在未被删除的边e(u,v))
删除边e(u,v)
DFS(v)
End
PathSize ← PathSize + 1
Path[ PathSize ] ← u
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std; const int N = ;
int n, m, flag, top, sum, du[N], ans[], map[N][N]; void dfs(int x)
{
ans[++top] = x;
for(int i = ; i <= n; i++)
{
if(map[x][i] >= )
{
map[x][i]--;
map[i][x]--;
dfs(i);
break;
}
}
} void fleury(int x)
{
top = ;
ans[top] = x;
while(top > )
{
int k = ;
for(int i = ; i <= n; i++)//判断是否可扩展
{
if(map[ans[top]][i] >= )//若存在一条从ans[top]出发的边 那么就是可扩展
{k = ; break;}
}
if(k == )//该点x没有其他的边可以先走了(即不可扩展), 那么就输出它
{
printf("%d ", ans[top]);
top--;
}
else if(k == )//如可扩展, 则dfs可扩展的哪条路线
{
top--;//这需要注意
dfs(ans[top+]);
}
}
}
int main()
{
while(scanf("%d%d", &n, &m) != EOF)
{
memset(du, , sizeof(du));
memset(map, , sizeof(map)); for(int i = ; i <= m; i++)
{
int x, y;
scanf("%d%d", &x, &y);
map[x][y]++; //记录边, 因为是无向图所以加两条边, 两个点之间可能有多条边
map[y][x]++;
du[x]++;
du[y]++;
}
flag = ; // flag标记开始点。 如果所有点度数全为偶数那就从1开始搜
sum = ;
for(int i = ; i <= n; i++)
{
if(du[i] % == )
{
sum++;
flag = i;// 若有奇数边, 从奇数边开始搜
}
}
if(sum == || sum == )
fleury(flag);
}
return ;
}
 

hiho欧拉路·二 --------- Fleury算法求欧拉路径的更多相关文章

  1. HihoCoder1181欧拉路(Fleury算法求欧拉路径)

    描述 在上一回中小Hi和小Ho控制着主角收集了分散在各个木桥上的道具,这些道具其实是一块一块骨牌. 主角继续往前走,面前出现了一座石桥,石桥的尽头有一道火焰墙,似乎无法通过. 小Hi注意到在桥头有一张 ...

  2. Fleury算法求欧拉路径

    分析: 小Ho:这种简单的谜题就交给我吧! 小Hi:真的没问题么? <10分钟过去> 小Ho:啊啊啊啊啊!搞不定啊!!!骨牌数量一多就乱了. 小Hi:哎,我就知道你会遇到问题. 小Ho:小 ...

  3. HihoCoder1182 欧拉路(Fleury算法)

    描述 小Hi和小Ho破解了一道又一道难题,终于来到了最后一关.只要打开眼前的宝箱就可以通关这个游戏了. 宝箱被一种奇怪的机关锁住: 这个机关是一个圆环,一共有2^N个区域,每个区域都可以改变颜色,在黑 ...

  4. hihocoder 1181 欧拉路.二

    传送门:欧拉路·二 #1181 : 欧拉路·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在上一回中小Hi和小Ho控制着主角收集了分散在各个木桥上的道具,这些道具其 ...

  5. [hihoCoder] 第五十周: 欧拉路·二

    题目1 : 欧拉路·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在上一回中小Hi和小Ho控制着主角收集了分散在各个木桥上的道具,这些道具其实是一块一块骨牌. 主角 ...

  6. hihoCoder #1181: 欧拉路·二 (输出路径)

    题意: 给定一个图,要求打印出任一条欧拉路径(保证图肯定有欧拉路). 思路: 深搜的过程中删除遍历过的边,并在回溯时打印出来.在深搜时会形成多个环路,每个环都有一个或多个结点与其他环相扣,这样就可以产 ...

  7. Fleury算法 求欧拉回路

    Fleury算法 #include <iostream> #include <cstdio> #include <cstring> #include <cma ...

  8. hiho 1098 最小生成树二·Kruscal算法 (最小生成树)

    题目: 时间限制:10000ms 单点时限:1000ms 内存限制:256MB   描述 随着小Hi拥有城市数目的增加,在之间所使用的Prim算法已经无法继续使用了——但是幸运的是,经过计算机的分析, ...

  9. 【HIHOCODER 1181】欧拉路·二

    描述 在上一回中小Hi和小Ho控制着主角收集了分散在各个木桥上的道具,这些道具其实是一块一块骨牌. 主角继续往前走,面前出现了一座石桥,石桥的尽头有一道火焰墙,似乎无法通过. 小Hi注意到在桥头有一张 ...

随机推荐

  1. AngularJS应用的解析

    模板(Templates) 模板是您用HTML和CSS编写的文件,展现应用的视图. 您可给HTML添加新的元素.属性标记,作为AngularJS编译器的指令. AngularJS编译器是完全可扩展的, ...

  2. 亦步亦趋在CentOS 6.4下安装Oracle 11gR2(x64)

    安装前须知: 内存(RAM)的最小要求是 1GB,建议 2GB 及以上. 虚拟内存 swap 建议:内存为 1GB~2GB 时建议swap大小为内存大小的 1.5 倍:内存为 2GB~16GB 时建议 ...

  3. 机器学习笔记之遗传算法(GA)

    遗传算法是一种大致基于模拟进化的学习方法,假设常被描述为二进制串.在遗传算法中,每一步都根据给定的适应度评估准则去评估当前的假设,然后用概率的方法选择适应度最高的假设作为产生下一代的种子.产生下一代的 ...

  4. 理解 strcpy方法

    char* strcpy(char* strDest, const char* strSrc) { assert((strDest!=NULL) && (strSrc !=NULL)) ...

  5. android 用ListView实现表格样式

    原文:http://blog.csdn.net/centralperk/article/details/8016350 效果图: 源码下载地址:http://download.csdn.net/det ...

  6. [ES6] 17. Set

    Es6 provides "Set", it likes array but the data inside should be unqiue. "Set" i ...

  7. iOS开发——图形与动画篇OC篇&图层基本上动画

    图层的一些基本动画效果 #define kRadianToDegrees (radian) (radian * 180.0) / (M_PI) //闪烁 [self.testView.layer ad ...

  8. MySQL · 特性分析 · innodb 锁分裂继承与迁移

    http://mysql.taobao.org/monthly/2016/06/01/ innodb行锁简介 行锁类型 LOCK_S:共享锁 LOCK_X: 排他锁 GAP类型 LOCK_GAP:只锁 ...

  9. Date Format, 时间戳格式化

    // 对Date的扩展,将 Date 转化为指定格式的String // 月(M).日(d).小时(h).分(m).秒(s).季度(q) 可以用 1-2 个占位符, // 年(y)可以用 1-4 个占 ...

  10. LeetCode: Binary Tree Traversal

    LeetCode: Binary Tree Traversal 题目:树的先序和后序. 后序地址:https://oj.leetcode.com/problems/binary-tree-postor ...