欧拉回路与欧拉路径
若图G中存在这样一条路径,从某个顶点出发,使得它恰通过G中每条边一次(通过每一个顶点可以多次),则称该路径为欧拉路径。若该路径是一个圈(回到起点),则称为欧拉(Euler)回路。
欧拉回路与欧拉路径的充要条件:
1)无向图存在欧拉回路的充要条件:一个无向图存在欧拉回路,当且仅当该图所有顶点度数都为偶数,且该图是连通图。
2)有向图存在欧拉回路的充要条件:一个有向图存在欧拉回路,所有顶点的入度等于出度且该图是连通图。
判断无向图是否存在欧拉回路:(1)图联通(dfs或者并查集判图联通)(2)所有顶点的度数均是偶数
判断有向图是否存在欧拉回路:(1)底图(忽略边方向后的无向图)联通(2)每个顶点的入度等于出度
判断无向图是否存在欧拉路径:(1)图联通(dfs或者并查集判图联通)(2)仅有2个顶点(起点和终点)的度数为奇数,其他顶点的度数均是偶数。
判断有向图是否存在欧拉路径:(1)底图(忽略边方向后的无向图)联通(2)只有两个点的入度不等于出度,并且其中一个点出度恰好比入度大1,另一个恰好入度比出度小1,每个顶点其它每个点的入度等于出度
1.http://poj.org/problem?id=2230
本题目构建图时,每一对顶点添加两条方向相反的边。题目已经说一定具有回路,所以采用dfs从顶点1开始对边进行不重复的遍历一次即可,当所有边遍历完后,回到考虑起始点。
//---dfs求欧拉回路
#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 10000 + 5;
struct edge{
int v;
bool vis;
edge(int i = 0) :v(i){ vis = 0; }
};
vector<edge>G[maxn];
void dfs(int u){
for (int i = 0; i < G[u].size(); i++){
edge &e = G[u][i];
if (!e.vis){
e.vis = true;
dfs(e.v);
}
}
printf("%d\n", u);
}
int main(){
int u, v, m, n;
while (~scanf("%d%d", &n, &m)){
for (int i = 0; i <=n; i++)G[i].clear();
for (int i = 0; i < m; i++){
scanf("%d%d", &u, &v);
G[u].push_back(edge(v));
G[v].push_back(edge(u));
}
dfs(1);
}
return 0;
}
2.http://poj.org/problem?id=2337
首先用并查集判断是否可以构成欧拉回路。然后确定可以构成欧拉回路后再用dfs搜索出最小字典序点的欧拉道路。如果事先没有判断是否可以构成欧拉回路直接爆DFS来搜索,将会耗去大量时间。
//---dfs求欧拉回路
#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 1000 + 5;
const int maxsize = 26;
struct Edge{
Edge(int a = 0, int b = 0) :v(a), id(b), vis(0){}
int v;
int id;//char str[maxsize];
bool vis;
};
char str[maxn][maxsize];
int p[maxn];
int deg[26];
vector<Edge>G[maxsize];
int n;
bool ans;
int used[26];
int parent[26];
int getparent(int i){
if (parent[i] == -1)return i;
return parent[i] = getparent(parent[i]);
}
bool cmp(Edge a, Edge b){
return strcmp(str[a.id], str[b.id])<0;
}
void dfs(int u, int curr){
if (curr == n){
ans = 1;
printf("%s", str[p[0]]);
for (int i = 1; i < n; i++)printf(".%s",str[p[i]]);
printf("\n");
return;
}
if (ans)return;
for (int i = 0; i < G[u].size(); i++){
Edge&e = G[u][i];
if (!e.vis){
e.vis = 1;
p[curr] = e.id;
dfs(e.v, curr + 1);
e.vis = 0; //撤回标志
}
}
}
int main(){
int T, i, u, v;
scanf("%d", &T);
while (T--){
memset(deg, 0, sizeof(deg));
memset(used, 0, sizeof(used));
memset(parent, -1, sizeof(parent));
for (i = 0; i < 26; i++)G[i].clear();
scanf("%d", &n);
int cc = 26;//联通块;
for (i = 0; i < n; i++){
scanf("%s", str[i]);
u = str[i][0] - 'a';
v = str[i][strlen(str[i]) - 1] - 'a';
deg[u]++; deg[v]--;
used[u] = used[v] = 1;
G[u].push_back(Edge(v, i));
u = getparent(u); v = getparent(v);
if (u != v){
cc--;
parent[u] = v;
}
}
vector<int>d;
for (i = 0; i < 26; i++){
if (!used[i])cc--;
else if (deg[i])d.push_back(deg[i]);
}
ans = 0;
if (cc == 1 && (d.empty() || d.size() == 2 && (d[0] == -1 || d[0] == 1)))ans = 1;
if (ans == 0){
printf("***\n"); continue;
}
for (i = 0; i < 26; i++)
sort(G[i].begin(), G[i].end(), cmp);
if (d.size() == 2){
for (i = 0; i < n; i++){
if (deg[i] == 1)break;
}
}
else{
i = 0;
while (!used[i])i++;
}
ans = 0;
dfs(i, 0);
}
return 0;
}

浙公网安备 33010602011771号