寻找欧拉路

寻找欧拉路

Time Limit:10000MS  Memory Limit:65536K
Total Submit:49 Accepted:27
Case Time Limit:1000MS

Description

如果图存在一笔画,则一笔画的路径称为欧拉路

Input

第一行n,m,有n个点,m条边,以下描述每条边连接的两点。

Output

欧拉或欧拉回路

Sample Input

5 5 
1 2
2 3
3 4
4 5
5 1

Sample Output

1 5 4 3 2 1

从起点开始有相邻节点继续搜

  • const
      maxn=100;
    var
      a:array[0..maxn,0..maxn] of longint;
      ans,b:array[0..maxn] of longint;
      i,j,n,m,s,p:longint;
    
    procedure find(i:longint);
    var
      j:longint;
    begin
      for j:=1 to n do
        if a[i,j]=1 then
          begin
            a[i,j]:=0;
            a[j,i]:=0;
            find(j);
          end;
      inc(s);
      ans[s]:=i;
    end;
    
    begin
      readln(n,m);
      for i:=1 to m do
        begin
          readln(j,p);
          a[j,p]:=1;
          a[p,j]:=1;
          inc(b[j]);
          inc(b[p]);
        end;
      p:=1;
      for i:=1 to n do
        if b[i] mod 2=1 then p:=i;
      find(p);
      for i:=1 to s do
        write(ans[i],' ');
    end.

优化一下下面的代码#include <stdio.h> #define N 100 //最大节点数 #define M 10000 //最大边数 int r[N][N]; //邻接矩阵 int degree[N]; //每个节点的度数 int sequence[M]; //欧拉经过的边的序号 int count = 0; //欧拉的数量 int n, m; //节点数和边数 //判断是否是欧拉图 int is_euler_graph() { int i; for (i = 1; i <= n; i++) { if (degree[i] % 2 != 0) { return 0; //有一个节点的度数是奇数,不是欧拉图 } } return 1; } //判断是否是欧拉 int is_euler_circuit() { int i; for (i = 1; i <= n; i++) { if (degree[i] != 0) { break; //找到一个非孤立点 } } if (i > n) { return 0; //所有节点都是孤立点,不是欧拉 } for (i = 1; i <= n; i++) { if (degree[i] % 2 != 0) { return 0; //有一个节点的度数是奇数,不是欧拉 } } return 1; } //寻找欧拉 void find_euler_path(int cur) { int i, j; for (i = 1; i <= n; i++) { if (r[cur][i]) { r[cur][i] = r[i][cur] = 0; //删除当前边 for (j = 1; j <= m; j++) { if (sequence[j] == 0) { sequence[j] = cur * 100 + i; //记录访问的边 break; } } find_euler_path(i); //递归寻找下一条边 break; } } } int main() { int i, j, x, y; printf("请输入节点数和边数:"); scanf("%d%d", &n, &m); for (i = 1; i <= m; i++) { printf("请输入第%d条边的起点和终点:", i); scanf("%d%d", &x, &y); r[x][y] = r[y][x] = 1; //无向图,边是双向的 degree[x]++; degree[y]++; } if (is_euler_graph()) { printf("这是一个欧拉图\n"); if (is_euler_circuit()) { printf("这是一个欧拉欧拉如下:\n"); find_euler_path(1); for (i = 1; i <= m; i++) { printf("%d -> %d\n", sequence[i] / 100, sequence[i] % 100); } } else { printf("这不是一个欧拉,但是有欧拉欧拉如下:\n"); for (i = 1; i <= n; i++) { if (degree[i] % 2 != 0) { break; } } find_euler_path(i); for (j = 1; j <= m; j++) { if (sequence[j] == 0) { break; } } for (i = j - 1; i >= 1; i--) { printf("%d -> %d\n", sequence[i] / 100, sequence[i] % 100); } } } else { printf("这不是一个欧拉图\n"); } return 0; }
06-12
### 欧拉径的寻找算法实现(无向图) 在无向图中寻找欧拉径的算法主要有两种:**Hierholzer 算法**和**Fleury 算法**。两者都能有效找出欧拉径,但实现方式和适用条件略有不同。 #### Hierholzer 算法 该算法基于深度优先搜索(DFS),通过递归回溯的方式构建径。当图中存在两个奇数度数的顶点时,必须从其中一个顶点开始执行算法,才能找到完整的欧拉径。这是因为欧拉径的起点和终点必须是这两个奇数度数的顶点之一[^1]。 以下是一个基于 C++ 的实现: ```cpp #include <iostream> #include <vector> #include <stack> using namespace std; const int MAXN = 1002; vector<int> graph[MAXN]; void hierholzer(int start) { stack<int> path; stack<int> current_path; current_path.push(start); while (!current_path.empty()) { int v = current_path.top(); if (!graph[v].empty()) { int u = graph[v].back(); graph[v].pop_back(); graph[u].remove(v); // 删除反向边 current_path.push(u); } else { path.push(v); current_path.pop(); } } // 输出径 while (!path.empty()) { cout << path.top() << " "; path.pop(); } cout << endl; } ``` #### Fleury 算法 Fleury 算法的核心思想是优先选择非桥边(即删除该边后不会导致图不连通的边)进行遍历。这种方法在实现上需要频繁判断某条边是否为桥,因此效率略低于 Hierholzer 算法。以下是一个基于 Python 的实现[^2]: ```python def find_eulerian_path(graph): path = [] stack = [next(iter(graph))] # 选择任意起点 while stack: v = stack[-1] if graph[v]: u = graph[v].pop() graph[u].remove(v) stack.append(u) else: path.append(stack.pop()) return path[::-1] ``` #### 算法适用条件 - 图必须是连通的。 - 顶点的度数满足以下条件之一: - 所有顶点的度数均为偶数,则存在欧拉。 - 恰好有两个顶点的度数为奇数,则存在欧拉径[^1]。 #### 算法复杂度 - 时间复杂度:两种算法的时间复杂度均为 $ O(E) $,其中 $ E $ 为图中边的数量。 - 空间复杂度:与图的存储结构相关,通常也为 $ O(V + E) $。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值