12.3 Reverse-Delete算法

算法描述

  算法的核心思想比较简单,与前三个算法都不同,它是把边按长度逆序排序,每次删除最长的边,直到图变成树为止。我举个例子,以下是图:
在这里插入图片描述
  最长的是10,删掉:
在这里插入图片描述
  接下来就是长度为9的两个了,删掉,没问题的:
在这里插入图片描述
在这里插入图片描述
  接下来就是为8的,删除一个:
在这里插入图片描述
  剩下的这个长度为8的可不能删除了,因为删除了就不连通了。那就还剩下长度为7的,删掉它:
在这里插入图片描述
  还有长度为6的,完全可以删除,但是删除之后,边的数量就是 n − 1 n-1 n1了,满足树的条件,不能继续删除了:
在这里插入图片描述

Python实现

  原理清楚之后,代码就任意写了,以下是python代码:

# _*_ coding:utf-8
import functools


class Edge:

    def __init__(self, to, weight):
        self.__to = to
        self.__weight = weight

    @property
    def to(self):
        return self.__to

    @property
    def weight(self):
        return self.__weight

    def __str__(self):
        return f'->{self.__to}(w={self.__weight})'

    def __repr__(self):
        return f'->{self.__to}(w={self.__weight})'


# wu
class WeightedGraph:
    def __init__(self, vertices, edges, pos):
        self.__vertices = vertices
        self.__edges = edges
        # 用于图形化
        self.__pos = pos

    @property
    def vertices(self):
        return self.__vertices

    @property
    def edges(self):
        return self.__edges

    def reverse_delete(self):
        all_edges = []
        for i, edges in enumerate(self.__edges):
            for edge in edges:
                if i > edge.to:
                    all_edges.append((i, edge))
        all_edges.sort(key=functools.cmp_to_key(lambda x, y: x[1].weight - y[1].weight))
        # 拷贝一套边
        a = [edges[:] for edges in self.__edges]
        x = WeightedGraph(self.__vertices, a, pos=self.__pos)
        n = len(self.__vertices)
        while x.is_connected() and len(all_edges) > n - 2:
            edge = all_edges.pop()
            # 双向删除边
            f = edge[0]
            t = edge[1].to
            if edge[1] in a[f]:
                a[f].remove(edge[1])
            reversed_edge = None
            for i, e in enumerate(a[t]):
                if e.to == f:
                    a[t].pop(i)
                    reversed_edge = e
                    break
            if not x.is_connected():
                # 加回去
                a[f].append(edge[1])
                a[t].append(reversed_edge)
            else:
                print(len(all_edges), x.to_dot())
        return a

    WHITE = 0
    GRAY = 1
    BLACK = 2

    def is_connected(self):
        colors = [WeightedGraph.WHITE for _ in self.__vertices]
        colors[0] = WeightedGraph.GRAY
        stack = [0]
        count = 0
        while len(stack) > 0:
            u = stack.pop()
            count += 1
            for v in self.__edges[u]:
                if colors[v.to] == WeightedGraph.WHITE:
                    stack.append(v.to)
                    colors[v.to] = WeightedGraph.GRAY
            colors[u] = WeightedGraph.BLACK
        return count == len(self.__vertices)

    def to_dot(self):
        pos = self.__pos
        dot_s = 'graph s {\n\tlayout=fdp\n'
        for i, v in enumerate(self.__vertices):
            dot_s += f'\t"{v}"[pos="{pos[i]}"];\n'
        for i, e in enumerate(self.__edges):
            for t in e:
                if t.to < i:
                    continue
                dot_s += f'\t\"{self.__vertices[i]}\"--"{self.__vertices[t.to]}"[label="{t.weight}"];\n'
        dot_s += '}\n'
        return dot_s

Python测试代码

import unittest

from com.youngthing.graph.reverse_delete import Edge, WeightedGraph

class ReverseDeleteTestCase(unittest.TestCase):
    def test_reverse_delete(self):
        # 做一张图
        vertices = ['A', 'B', 'C', 'D', 'E', 'F', 'G', ]
        # 设计容量
        edges = [
            [Edge(1, 4), Edge(2, 8), ],  # a
            [Edge(0, 4), Edge(2, 9), Edge(3, 8), Edge(4, 10)],  # B
            [Edge(0, 8), Edge(1, 9), Edge(3, 2), Edge(5, 1)],  # C
            [Edge(1, 8), Edge(2, 2), Edge(4, 7), Edge(5, 9)],  # D
            [Edge(1, 10), Edge(3, 7), Edge(5, 5), Edge(6, 6)],  # E
            [Edge(2, 1), Edge(3, 9), Edge(4, 5), Edge(6, 2)],  # f
            [Edge(4, 6), Edge(5, 2)],  # g
        ]
        pos = ["0,0!", "2,1!", "2,-1!", "4,0!", "6,1!", "6,-1!", "8,0!", ]
        fn = WeightedGraph(vertices, edges, pos)

        print(fn.to_dot())

        tree = fn.reverse_delete()
        print(WeightedGraph(vertices, tree, pos).to_dot())


if __name__ == '__main__':
    unittest.main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

醒过来摸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值