四个重要定理
无向图存在欧拉通路的条件:连通且只有两个顶点的度是奇数,其余都是偶数,或者无度为奇数的结点
无向图存在欧拉回路的条件:连通且所有节点的度为偶数有向图存在欧拉通路的条件:连通且所有顶点的出度与入度都相等,或者除两个顶点外,其余顶点的出度与入度都相等,而这两个顶点中一个顶点的出度比入度之大1,另一个顶点的出度比入度小1。
有向图存在欧拉回路的条件:连通且所有的顶点出度等于入度
记住以上几个定理就好办了,下面是两个例题:
一、无向图的欧拉回路
题目链接:HDU 1878 欧拉回路
根据如上定理,借助并查集检查图是否连通,再使用indegree数组记录节点的度,AC代码如下:
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
const int MAXN = 1005;
//无向图的欧拉回路
//http://acm.hdu.edu.cn/showproblem.php?pid=1878
//HDU Accepted 1878 78MS 1404K 980 B G++
int indegree[MAXN];
int f[MAXN];
//vector<node> G;
int find(int x) {
if(x == f[x]) return x;
return f[x] = find(f[x]);
}
void Union(int x, int y) {
int fx = find(x);
int fy = find(y);
if(fx != fy)
f[fx] = fy;
}
int main() {
int n, m, u, v;
while(~scanf("%d", &n)) {
if(n == 0) break;
int cnt = 0;
memset(indegree, 0, sizeof(indegree));
for(int i=1; i<=n; i++) f[i] = i;
scanf("%d", &m);
for(int i=0; i<m; i++) {
scanf("%d%d", &u, &v);
indegree[u]++;
indegree[v]++;
Union(u, v);
}
bool flag = 0;
int num = 0;
for(int i=1; i<=n; i++) {
if(indegree[i] & 1) {
//奇顶点
flag = 1;
break;
}
}
if(flag == 1) {
cout<<0<<endl;
continue;
}
else {
//连通?
for(int j=1; j<=n; j++) {
if(f[j] == j)
num++;
}
if(num == 1)
cout<<1<<endl;
else
cout<<0<<endl;
}
}
return 0;
}
二、有向图的欧拉通路
题目链接:HDU 1116 Play on Words
思路依旧是使用并查集判断图的连通性,再使用indegree记录节点入度,outdegree记录节点出度。根据定理判断是否有欧拉通路。AC代码如下:
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
const int MAXN = 100005;
//HDU Accepted 1116 1076MS 2188K 1601 B G++
int f[MAXN];
int indegree[MAXN];
int outdegree[MAXN];
int flag[2] = {0, 0};
bool vis[27]; //这个字母是否出现过
int find(int x) {
if(x == f[x]) return x;
return f[x] = find(f[x]);
}
void Union(int u, int v) {
int fu = find(u);
int fv = find(v);
if(fu != fv)
f[fu] = fv;
}
int main() {
int t, n;
string word;
cin>>t;
while(t--) {
cin>>n;
for(int i=0; i<26; i++) f[i] = i;
memset(indegree, 0, sizeof(indegree));
memset(outdegree, 0, sizeof(outdegree));
memset(vis, 0, sizeof(vis));
for(int i=0; i<n; i++) {
cin>>word;
int u = (int)word[0] - 'a';
int v= (int)word[word.length()-1] - 'a';
// cout<<u<<" "<<v<<endl;
vis[u] = vis[v] = 1;
outdegree[u]++;
indegree[v]++;
Union(u, v);
}
//判断是否连通
int cnt = 0;
int num = 0;
for(int i=0; i<26; i++)
if(f[i] == i && vis[i])
cnt++;
if(cnt == 1) {
//连通
for(int j=0; j<26; j++) {
if(vis[j] && indegree[j] != outdegree[j]) {
flag[num] = j;
num++; //出度入度不相等的节点数
}
}
if(num == 0)
cout<<"Ordering is possible."<<endl;
else if(num == 2) {
int cha1 = indegree[flag[0]] - outdegree[flag[0]];
int cha2 = indegree[flag[1]] - outdegree[flag[1]];
if((cha1 == 1 && cha2 == -1) || (cha1 == -1 && cha2 == 1)) {
cout<<"Ordering is possible."<<endl;
}
else
cout<<"The door cannot be opened."<<endl;
}
else
cout<<"The door cannot be opened."<<endl;
}
else {
cout<<"The door cannot be opened."<<endl;
}
}
return 0;
}