图算法-欧拉路径

哈密尔顿回路: 从一个点出发,沿着边行走,经过每个顶点恰好一次,之后再回到出发点

欧拉回路: 从一个点出发,沿着边行走,经过每个边恰好一次,之后再回到出发点

欧拉回路性质: 对于无向连通图, 每个点的度是偶数 <-----> 图存在欧拉回路

判断图中有没有欧拉回路:

Hierholzer 算法:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

# encoding = 'utf-8'

from copy import copy
from sortedcontainers import SortedSet as TreeSet


class CC:
    def __init__(self, G):
        self._G = G
        self._visited = [False] * G.V
        self._ccount = 0
        for v in range(G.V):
            if not self._visited[v]:
                self._dfs_recursive(v)
                self._ccount += 1

    def _dfs_recursive(self, v):
        self._visited[v] = True
        for w in self._G.adj(v):
            if not self._visited[w]:
                self._dfs_recursive(w)

    @property
    def ccount(self):
        return self._ccount


class Graph:
    def __init__(self, filename):
        self._filename = filename
        lines = None
        with open(filename, 'r') as f:
            lines = f.readlines()
        if not lines:
            raise ValueError('Expected something from input file!')

        # lines[0] -> V E
        self._V, self._E = (int(i) for i in lines[0].split())

        if self._V < 0:
            raise ValueError('V must be non-negative')

        if self._E < 0:
            raise ValueError('E must be non-negative')

        # size V list of TreeSet
        self._adj = [TreeSet([]) for _ in range(self._V)]
        for each_line in lines[1:]:
            a, b = (int(i) for i in each_line.split())
            self.validate_vertex(a)
            self.validate_vertex(b)

            if a == b:
                raise ValueError('Self-Loop is detected!')

            if b in self._adj[a]:
                raise ValueError('Paralles edges are detected!')

            self._adj[a].add(b)
            self._adj[b].add(a)

    @property
    def V(self):
        return self._V

    @property
    def E(self):
        return self._E

    def has_edge(self, v, w):
        self.validate_vertex(v)
        self.validate_vertex(w)
        return w in self._adj[v]

    def adj(self, v):
        self.validate_vertex(v)
        return self._adj[v]

    def degree(self, v):
        return len(self.adj(v))

    def remove_edge(self, v, w):
        self.validate_vertex(v)
        self.validate_vertex(w)
        if w in self._adj[v]:
            self._adj[v].remove(w)
        if v in self._adj[w]:
            self._adj[w].remove(v)

    def validate_vertex(self, v):
        if v < 0 or v >= self._V:
            raise ValueError('vertex ' + str(v) + ' is invalid')

    def __str__(self):
        res = ['V = {}, E = {}'.format(self._V, self._E)]
        for v in range(self._V):
            res.append('{}: {}'.format(v, ' '.join(str(w) for w in self._adj[v])))
        return '\n'.join(res)

    def __repr__(self):
        return self.__str__()

    def __copy__(self):
        return Graph(self._filename)


class EulerLoop:
    def __init__(self, G):
        self._G = G

    def has_euler_loop(self):
        cc = CC(self._G)
        if cc.ccount > 1:
            return False

        for v in range(self._G.V()):
            if self._G.degree(v) % 2 != 0:
                return False

        return True

    def result(self):
        res = []
        if not self.has_euler_loop:
            return res
        g = copy(self._G)

        stack = []
        currv = 0
        stack.append(currv)

        while stack:
            if g.degree(currv) != 0:
                stack.append(currv)
                # 模拟一个iterator
                w = next(self._iter_next_adj(g.adj(currv)))
                g.remove_edge(currv, w)
                currv = w
            else:
                # 此时说明找到了一个环
                res.append(currv)
                currv = stack.pop()

        return res

    def _iter_next_adj(self, adj):
        yield from sorted(adj)


if __name__ == '__main__':
    filename = 'g.txt'
    g = Graph(filename)
    eluer_loop = EulerLoop(g)
    print(eluer_loop.result())

    filename = 'g2.txt'
    g = Graph(filename)
    eluer_loop = EulerLoop(g)
    print(eluer_loop.result())

 

g.txt


5 6
0 1
0 2
1 2
2 3
2 4
3 4


g2.txt

11 15
0 1
0 3
1 2
1 4
1 5
2 5
3 4
4 5
4 6
5 7
6 7
7 8
7 9
8 10
9 10

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值