hdu1116 欧拉图的判定(点的度数的判定+用非递归的路径压缩的并查集/dfs对连通图的判定)

这篇博客讨论了如何将单词排列问题转化为欧拉图的判定,分析了无向图和有向图成为欧拉图的条件,并探讨了在解决此类问题时使用dfs和并查集的优缺点。通过实例展示了在限制内存的情况下,如何利用并查集高效地判断图的连通性,避免了递归带来的栈溢出和存储所有边可能导致的内存超限问题。
摘要由CSDN通过智能技术生成

0)

题意:  给出一些单词,能否将所有单词(每个单词都要用上,给出几次就用几次)排成一列,且第i个单词的最后一个字母总是等于第i+1个单词的第一个字母。


分析:①这道题先转化成图的模型,每个单词的首字母和尾字母是图中的点,而单词是有向边。

            ②对于题目所要求的,寻找是否可以走完每条边且每条边只走一次,就变成了离散数学上的对于一个图是否是欧拉图(两种,是欧拉道路和欧拉回路)的判定。

            ③对于无向图有两个条件:要求该图是连通的,图中全为偶数度数的点或者有最多有两个奇点  (度数为奇数的点为奇点);

                对于有向图有两个条件:要求该图在忽略方向的情况下是连通的,图中全为偶数度数的点或者最多有两个奇点且其中一个点的入度比出度多1、另一个点的出度比入度多1。

            ④对于度数,建个数组每个点存一下出现的次数即可;对于判断图是否连通,可以用dfs或者并查集。


参考:

并差集及其优化(路径压缩和按秩合并)

趣讲并查集


自己做题时:  刚开始想仅仅用dfs并不用欧拉图相关知识,即每个单词的第一个字母和最后一个字母作为点,按照有向边进行深搜,直到所有边都被纳入,但是递归最高可能10^5次会超出栈的容量。如果用不递归的写法应该很麻烦,因为题意是要把所有单词都用一遍,而并不是单纯将所有点都遍历一遍,单纯用dfs找出是否有这样的路径并不容易。况且如下面第二份Memory Limit Exceeded代码中建立一个结构体数组,每个结构体里再建立一个字符数组,如果要满足题意则是(10^5)*(10^3)的个数,每个char两个字节(byte),就是2*(10^5)*(10^3) b,即2*(10^5)*(10^3) /1024 KB,约等于10^5KB的规模,而题目要求是小于32768KB,会超内存Memory Limit Exceeded,所以将所有边进行存储并不现实。每条边只存单词的首字母和尾字母或许可以一试.但不如用并查集更简单,只需要用两个长度大于26的数组存储26个字母即可,存储他们的入度和出度,然后10^5的边就不需要再存储了,一边输入一边再整理并查集,输入完毕以后看看所有的点的上级节点是不是同一个即可。如果单纯求图是否联通,用dfs也是可以的,与并查集都是O(n)时间复杂度,但是并查集应该稍微省一点内存(比如说,用dfs最先想到的是用二维的邻接矩阵存储(长、宽都是26)边,从任意一点出发进行深搜,每次遇到一个点就标记一下,结束之后扫描一下标记的数组,看看还有没有没标记的点。)

1)AC

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <string>


using namespace std;
//const int maxn=100010;
const int maxn1=1010;
int flag=1;
int n;
int cnt=0;
//char zimu[26]={'a','b','c','d','e','f
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值