欧拉路
欧拉路
概念
经过图中所有边恰好一次的通路称为欧拉通路或欧拉路
经过图中所有边恰好一次的回路称为欧拉回路
性质
无向图
对于无向图G,G中存在欧拉回路当且仅当G中所有度非0的点是连通的且没有奇数度数的点。
对于无向图G,G中存在欧拉路当且仅当G中所有度非0的点是连通的且G中恰有0或2个奇数度数的点(0个表示存在欧拉回路)。
有向图
对于有向图G,G中存在欧拉回路当且仅当G中所有度非0的点是强连通的且每个点的入度和出度相同。
对于有向图G,G中存在欧拉路当且仅当:
将G中所有有向边改为无向边后,G中所有度非0的点是连通的;
最多只有一个点的出度减去入度为1;
最多只有一个点的入度减去出度为1;
其他所有点的入度等于出度。
时间复杂度
求有向图欧拉通、回路:
VI edge[N + 1];
int n, m, l, f[N + 1], ind[N + 1], outd[N + 1], c[M + 2], v[N + 1];//ind[x],outd[x]表示出度和入度,c记录欧拉路,f[x]表示edge[x]的遍历情况
inline void dfs(int x) {
while (f[x] < v[x]) {//v[x]即edge[x].size()
int y = edge[x][f[x]];
f[x]++;
dfs(y);
c[++l] = y;
}
}
inline void Euler() {
int x = 0, y = 0, z = 0;
for (int i = 1; i <= n; i++) {//判断是否有欧拉路
if (ind[i] + 1 == outd[i])
x = i, ++y;
if (ind[i] != outd[i])
++z;
}
if (!((y == 1 && z == 2) || !z)) {
printf("No\n");
return;
}
if (!x)
for (int i = 1; i <= n; i++)
if (ind[i]) x = i;
memset(f, 0, sizeof(f));
l = 0;
dfs(x);
c[++l] = x;
if (l != m + 1) {//判断是否连通
printf("No\n");
return;
}
printf("Yes\n");
for (int i = l; i; --i)
printf("%d", c[i]);
}
void solve() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
int x, y;
scanf("%d%d", &x, &y);
edge[x].push_back(y);
++outd[x], ++ind[y];
}
for (int i = 1; i <= n; i++) {
v[i] = edge[i].size();
//若要输出字典序最小的欧拉路,则要排序
//sort(edge[i].begin(), edge[i].end());
}
Euler();
}求无向图欧拉通、回路
struct Node {
int y, idx;
Node(int _y, int _idx) { y = _y, idx = _idx; }
bool operator<(const Node& A) const {
return y < A.y;
}
};
vector<Node> edge[N + 1];
int n, m, l, cnt=1,f[N + 1], d[N + 1], c[M + 2], v[N + 1];//d[x]表示度数,c记录欧拉路,f[x]表示edge[x]的遍历情况,cnt记录边的编号
bool b[2 * M + 2];//判断这条边是否走过,走过为true
inline void dfs(int x) {
while (f[x] < v[x]) {//v[x]即edge[x].size()
int y = edge[x][f[x]].y, idx = edge[x][f[x]].idx;
if (!b[idx]) {
f[x]++;
b[idx] = b[idx ^ 1] = true;
dfs(y);
c[++l] = y;
}
else f[x]++;
}
}
inline void Euler() {
int x = 0, y = 0;
for (int i = 1; i <= n; i++) {//判断是否有欧拉路
if (d[i] & 1) x = i, ++y;
}
if (y && y != 2) {
printf("No\n");
return;
}
if (!x)
for (int i = 1; i <= n; i++)
if (d[i]){
x = i;
break;
}
memset(f, 0, sizeof(f));
memset(b, false, sizeof(b));
l = 0;
dfs(x);
c[++l] = x;
if (l != m + 1) {//判断是否连通
printf("No\n");
return;
}
printf("Yes\n");
for (int i = l; i; --i)
printf("%d", c[i]);
}
void solve() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
int x, y;
scanf("%d%d", &x, &y);
edge[x].push_back({ y,++cnt });
edge[y].push_back({ x,++cnt });
++d[x], ++d[y];
}
for (int i = 1; i <= n; i++) {
v[i] = edge[i].size();
//若要输出字典序最小的欧拉路,则要排序
//sort(edge[i].begin(), edge[i].end());
}
Euler();
}
Last updated