博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
UVa10054 - The Necklace(欧拉回路【输出带来的麻烦)
阅读量:4550 次
发布时间:2019-06-08

本文共 2606 字,大约阅读时间需要 8 分钟。

分析:

一开始我把每种颜色拆成两个点(下面都称为第一个点,第二个点)
如果一个珠子是左x右y
那就连接x2—>y1,规定这种边只能走一次
每种颜色都连接x2—>x1,规定这种边可以走无数次

这样建好图之后,从任一颜色的第一个点开始遍历

看能不能到达这一颜色的第二个点并且所有只能走一次的边都经过了

这样确实是可以解决这个问题

但是有些边可以经过无数次,在实际判断的时候有点困难

实际上是没有必要拆点的,

我们把每种颜色视为一个点,每个珠子的两半连一条无向边
则题目就转化成了欧拉回路问题

欧拉回路

若图G中存在这样一条路径,使得它恰通过G中每条边一次,则称该路径为欧拉路径。若该路径是一个圈,则称为欧拉(Euler)回路。

无向图的欧拉回路判断和路径输出:

1.判断所有的点的度是否为偶数,如果有点不为偶数,则不存在欧拉回路

2.满足1的条件下,判断所给的图是否连通,不连通也不是欧拉回路
3.满足1和2的就是欧拉回路,然后dfs逆序输出路径,主要一定要逆序

这道题不用判断是否连通

(题目比较良心,给出的图都是合法的)

Q.什么叫逆序输出?

A.

for (int i=1;i<=50;i++)    if (mp[now][i])    {        mp[now][i]--;        mp[i][now]--;        euler(i);        printf("%d %d\n",i,now);        //一定要逆序输出     }

Q.顺序输出是什么样呢

A.

printf("%d %d\n",now,i);euler(i);

Q.为什么不能顺序输出呢

A.
在输入的时候会有重边,也就是说mp[i][j]的值不一定只是为1
我们从一个点出发,找到和他相连的点,然后删除这条无向边,

mp[now][i]--;mp[i][now]--;

然后就去dfs下一个点v,最后在递归返回的时候才输出路径

之所以逆序输出
是因为和当前点i相连的点可能不止一个

例如当前点是1,上一条边是(3,1) .

而和1相连的点有2,7,11,能分成3个方向

往2的方向有 : (1,2)(2,4)

往7的方向有 : (1,7)(7,5)(5,6)
往11的方向有 : (1,11)(11,12)(12,13)

如果顺序输出将会是

3 1
1 2
2 4
1 7
7 5
5 6
1 11
11 12
12 13

计算机中,上述过程是这样的

从起点开始,将起点压入栈中,

然后访问与顶点相连的一个顶点,将该顶点压入栈中,同时删除这条边,
继续DFS寻找顶点,并同样压栈、删除,
最后,直到走到一个没有任何边与它相连的顶点(可能是起始点,也可能不是),
便开始进行回溯,
回溯的同时进行弹栈,弹栈的结果也就是欧拉回路的逆序输出结果
回溯的过程就是寻找相连路径的过程,
如果回溯的过程中发现仍然有边与当前顶点相连,
那么继续从这个顶点沿着未删除的边去DFS,同时进行压栈等一系列操作,
最后,必定会回到该点

相反的,如果正向输出,

可能会出现断掉的现象(从一个点突然跳到另一个点)

tip

点表示的是颜色

所以点的循环都是

1~50

要了解算法的内部实现

这样有助于避免一些玄学的错误

图论比数论难搞多了,就连bfs都有可能写错

可见,

不光要学会数学建模,
对于模型的简化也是很重要的

//这里写代码片#include
#include
#include
using namespace std;int n;const int N=55;int mp[N][N],in[N];void euler(int now){ for (int i=1;i<=50;i++) if (mp[now][i]) { mp[now][i]--; mp[i][now]--; euler(i); printf("%d %d\n",i,now); //一定要逆序输出 }}int main(){ int T; scanf("%d",&T); for (int TT=1;TT<=T;TT++) { memset(mp,0,sizeof(mp)); memset(in,0,sizeof(in)); scanf("%d",&n); int s; for (int i=1;i<=n;i++) { int u,w; scanf("%d%d",&u,&w); if (i==1) s=u; mp[u][w]++; mp[w][u]++; in[w]++; in[u]++; } printf("Case #%d\n",TT); int ff=1; for (int i=1;i<=50;i++) //点代表的是颜色,我们要判断所有的点 if (in[i]&1) { ff=0; break; } if (!ff) printf("some beads may be lost\n"); else { for (int i=1;i<=50;i++) euler(i); } if (TT!=T) puts(""); } return 0;}

转载于:https://www.cnblogs.com/wutongtong3117/p/7673013.html

你可能感兴趣的文章
4嵌入式作业io
查看>>
IntelliJ Idea编译报错:javacTask: 源发行版 1.7 需要目标发行版 1.7
查看>>
Cognos中新建SQLserver数据源的步骤
查看>>
HttpClient连接超时及读取超时
查看>>
SQL优化方法
查看>>
SEO必须掌握的高级搜索指令
查看>>
生产者消费者模型
查看>>
ORACLE 字符串超长问题解决方案
查看>>
使用ZooKeeper协调多台Web Server的定时任务处理(方案1)
查看>>
20171116 每周例行报告
查看>>
[C#] SHA1校验函数用法
查看>>
linux 下 VMware 提示Unable to change virtual machine power state:
查看>>
洛谷P1585 魔法阵
查看>>
线程 题待做
查看>>
PL/SQL可以连oracle,但是jdbc连不上 【转】
查看>>
使用 highlight.js 在网页中高亮显示java 代码 【原】
查看>>
Android应用 程序框架设计方法
查看>>
基于Nginx环境下5种http转https的设置方法
查看>>
windows创建服务
查看>>
锋利的JQuery —— JQuery性能优化
查看>>