欧拉回路与欧拉路径
- 欧拉回路 不重复地结果每条边的回路
- 欧拉路径 不重复地几个每条边地路径
- 欧拉图 存在欧拉回路地图
- 半欧拉图 存在欧拉路径地图
在数学中为简单的图的一笔画完问题,但在有向图里,可以应用到单词接龙判断
判断是否存在欧拉回路
- 无向图
- 有向图
- 混合图
无向图
欧拉回路
- 连通
- 每个顶点的入出度是偶数,则存在欧拉回路
欧拉路径 - 连通
- 只有两个点地入出度为奇数
这两个点为起点和终点
有向图
欧拉回路
- 连通
- 每个顶点的入度等于出度
欧拉路径
- 连通
- 某结点入度比出度大1,另一结点出度比入度大1;其余结点入度等于出度
混合图
既有有向图又有无向图
求无向图欧拉回路的算法
1.判断连通有两种方法,dfs和并查集
dfs复杂度O(n^2)
并查集
2.求度
例题
无向图判断欧拉回路
欧拉回路是指不令笔离开纸面,可画过图中每条边仅一次,且可以回到起点的一条回路。现给定一个图,问是否存在欧拉回路?
Input
测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是节点数N ( 1 < N < 1000 )和边数M;随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个节点的编号(节点从1到N编号)。当N为0时输入结
束。
Output
每个测试用例的输出占一行,若欧拉回路存在则输出1,否则输出0。
Sample Input
3 3
1 2
1 3
2 3
3 2
1 2
2 3
0
Sample Output
1
0
dfs+degree
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int maxn=1005; int g[maxn][maxn];//邻接矩阵 int du[maxn]; int vis[maxn]; int n,m; void dfs(int m){//把与第一个结点相连接的所有结点都遍历 vis[m]=1; for(int i=1;i<=n;i++){ if(g[m][i]==1&&vis[i]==0){//对于每个结点相连接的点,判断是否没有走过 dfs(i);//没走过就走 } } } int main(){ while(scanf("%d",&n)!=0&&n){ scanf("%d",&m); //初始化 memset(vis,0,sizeof(vis)); memset(g,0,sizeof(g)); memset(du,0,sizeof(du)); for(int i=0;i<m;i++){ int u,v; scanf("%d%d",&u,&v); g[u][v]=g[v][u]=1;//邻接矩阵 du[u]++; du[v]++;//度 } dfs(1); int flag=1; for(int i=1;i<=n;i++){ //连通的判断 if(!vis[i]){ flag=0; break; } //度的判断 if(du[i]%2){ flag=0; break; } } if(flag){ printf("1\n"); }else{ printf("0\n"); } } return 0; }
并查集+度
边输入边进行合并操作,如果树的根为本身,则进行合并
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=1005; int pre[maxn],dge[maxn]; int n,m; void init(){ for(int i=1;i<=n;i++){ dge[i]=0; pre[i]=i; } } int find(int x){//寻找根 while(x!=pre[x]){ x=pre[x]; } return x; } void unio(int i,int j){ pre[j]=find(i); } int main(){ while(scanf("%d",&n)!=EOF&&n){ scanf("%d",&m); //初始化 init(); for(int i=0;i<m;i++){ int u,v; scanf("%d%d",&u,&v); //度 dge[u]++; dge[v]++; if(find(u)!=find(v)){//如果两个xxx,则合并为一个树 unio(u,v); } } int flag=1; for(int i=1;i<=n;i++){//度的判断 if(dge[i]%2){ printf("0\n"); flag=0; break; } } if(flag==0)continue; int x=pre[1];//树的根 for(int i=2;i<=n;i++){ if(x!=find(i)){ flag=0; break; } } if(flag){ printf("1\n"); }else{ printf("0\n"); } } return 0; }
有向图判断欧拉回路
Description
Some of the secret doors contain a very interesting word puzzle. The team of archaeologists has to solve it to open that doors. Because there is no other way to open the doors, the puzzle is very important for us.
There is a large number of magnetic plates on every door. Every plate has one word written on it. The plates must be arranged into a sequence in such a way that every word begins with the same letter as the previous word ends. For example, the word "acm" can be followed by the word "motorola". Your task is to write a computer program that will read the list of words and determine whether it is possible to arrange all of the plates in a sequence (according to the given rule) and consequently to open the door.
Input
The input consists of T test cases. The number of them (T) is given on the first line of the input file. Each test case begins with a line containing a single integer number Nthat indicates the number of plates (1 <= N <= 100000). Then exactly Nlines follow, each containing a single word. Each word contains at least two and at most 1000 lowercase characters, that means only letters 'a' through 'z' will appear in the word. The same word may appear several times in the list.
Output
Your program has to determine whether it is possible to arrange all the plates in a sequence such that the first letter of each word is equal to the last letter of the previous word. All the plates from the list must be used, each exactly once. The words mentioned several times must be used that number of times.
If there exists such an ordering of plates, your program should print the sentence "Ordering is possible.". Otherwise, output the sentence "The door cannot be opened.".
Sample Input
3
2
acm
ibm
3
acm
malform
mouse
2
ok
ok
Sample Output
The door cannot be opened.
Ordering is possible.
The door cannot be opened.
给一组单词,判断按一定顺序是否可以形成欧拉路径
代码
x笔画完???
X笔画判断: 奇点数为1及2以上的图,奇点数为N,则X=N整除2
本题其实就是考察简单半欧拉图及其扩展定理,设顶点的度数为连接的边数,然后统计所有顶点中度数为奇数的顶点的个数n,则答案一定为n/2。
首先,根据握手定理,所有顶点的度数之和一定为偶数。则奇数顶点的个数一定为偶数。然后每画一笔,最多可以使奇数顶点个数减少两个(或者不减少),所以一定至少要n/2笔,才能把画画完。
有一个特殊情况,即为所有点构成一个环的情况。此时n=0,但实际上需要一笔画完(即欧拉图),所以需要特判一下。
给定一个无向图,包含n 个顶点(编号1~n),m 条边,求最少用多少笔可以画出图中所有的边
第一行2个数n,m
以下m行 每行2个数a,b(a<>b) 表示a,b两点之间有一条边相连
一条边不会被描述多次
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,m,num; int into[1010]; int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int u,v; scanf("%d%d",&u,&v); into[u]++; into[v]++; } for(int i=1;i<=n;i++){ if(into[i]%2!=0){ num++; } } if(num==0||num==2){ cout<<"1"; return 0; }else{ cout<<num/2; } }
附录:
vector的函数
push_back()在数组的最后添加一个数据
pop_back()在数组的最后删除一个数据
size()当前使用数据的大小
clear()清空当前的vector