lintcode 629. Minimum Spanning Tree 的思路与python实现

Given a list of Connections, which is the Connection class (the city name at both ends of the edge and a cost between them), find edges that can connect all the cities and spend the least amount.
Return the connects if can connect all the cities, otherwise return empty list.

思路

最小生成树问题

用kruskal算法,比较好理解,就是贪心算法,越短的边越要选。但是如果k个点其实只要k-1条边,如果两个点已经在一个图里就不需要边给它连上了,所以这样的边就不要。

  • 所有边按照权重排序,从小到大选择,如果选择的这个边的两端,已经在一个图里了,那就不要它,否则就要它。

但是怎么判断两个节点是否在一个图里呢?使用union-find(并查集)的方法。使用一个字典来记录每一个节点的爸爸。

  • 同一个图里的节点有一个共同的祖先作为他们的代表,想知道两个节点是不是在一个图里,就看他们的祖先是不是在一个图里。
  • 如果一个点的爸爸就是自己,说明他就是他这张图里的祖先了
  • 当所有点都还是孤立的时候,他们的爸爸就是他们自己。
  • 当AB两个点被连接起来了,那A家和B家就成一家了,就得把他们合并起来,具体做法就是把A点的祖先[老A]指向B点的祖先[老B]就好了。这样一来[老B]就是[老A]的爸爸,原来把[老A]当作祖先的人就会把[老B]当作祖先。
  • 这样做已经可以判断了。但是一直要递归的网上走会比较浪费时间,可以在每次调用find方法找祖先以后,直接把祖先当成爸爸,这样路径就短了。

代码

这个代码在beats 94.00% Submissions in lintcode。命名命得不咋地。

class Solution:
    # @param {Connection[]} connections given a list of connections
    # include two cities and cost
    # @return {Connection[]} a list of connections from results
    def lowestCost(self, connections):
        # Write your code here
        connections.sort(key=lambda c:(c.cost,c.city1,c.city2))
        ans = []
        group = {}
        def find(city):
            while group.get(city) != city:
                city = group.get(city)
            return city
        cityset = set()
        for con in connections:
            cityset.add(con.city1)
            cityset.add(con.city2)
                
        for con in connections:
            c1 = con.city1
            c2 = con.city2
            if c1 not in group.keys():
                group[c1] = c1
            if c2 not in group.keys():
                group[c2] = c2
            g1 = find(c1)
            g2 = find(c2)
            group[c1] = g1
            group[c2] = g2
            if g1 != g2:
                ans.append(con)
                group[g2] = g1
            
            if len(cityset) - 1 == len(ans):
                return ans
        return []

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值