[蓝桥杯] 网络寻路 python 满分解法

[蓝桥杯] 网络寻路 python 满分解法


前言

本人小白一枚,最近在准备python组的蓝桥杯,在此记录一下真题——网络寻路的满分解法~

方法一:回溯法

思路:

首先,我想到的第一种方法是回溯法。基本思路为先通过输入通过数据结构记录图的结构。然后以每一个元素为起点进行遍历。同时在这个过程中要保证每一条边不能重复出现,顶点只可以在开始的节点和结束的节点重复出现…,具体的思路不再描述了,因为不提倡这种方法。

时间复杂度:

O(N**4), 因为在最坏的情况下,每个顶点与其余n-1个顶点都会有边进行联系。所以我们遍历4个节点的时候就相当于for 循环了4遍,即使进行剪枝,仍然改变不了复杂度为N的四次方的事实

在这里插入图片描述

代码

如下:

#定义边的类,to表示它的终点,source_edge表示它的源点的另外一条出边
class Edge:
    def __init__(self,to=-1):
        self.to=to
        self.source_edge=-1

#方法一:回溯算法
## 时间复杂度O(n**4),
##因为在极端的情况下,每个顶点可能与另外的n-1条边连接。所以我们第一次遍历n的次数,第二次,第三次,第四次都是遍历n次数
#在dsf的过程中,第一保证每条边只使用一次       
class Solution:
    def networkRoads(self,n,m,edges) -> str:
        def addEdge(u,v):
            nonlocal cnt
            nonlocal lines_num
            edge_list[cnt].to=v
            edge_list[cnt].source_edge=pre[u]
            lines_num[u]+=1
            pre[u]=cnt
            cnt+=1
        def dsf(start,val):
            nonlocal flag
            nonlocal temp_second
            nonlocal ans_normal
            nonlocal ans_singlar
            nonlocal end_set
            if temp_second==0:
                temp_second=-1
            if start in end_set and flag==0:
                return
            if flag==2 and val==start:
                return
            if flag==1:
                temp_second=val
            if flag==3:
                if val==temp_second:
                    return            
                if lines_num[val]==1:
                    end_set.add(val)
                    ans_singlar+=1
                else:
                    ans_normal+=1
                return
            if val==-1:
                p=pre[start]
            else:
                p=pre[val]
            while p!=-1:                
                if not used[p//2]:
                    q=edge_list[p].to
                    flag+=1
                    used[p//2]=True
                    dsf(start,q)
                    used[p//2]=False
                    flag-=1
                p=edge_list[p].source_edge
            return 
        cnt=0
        lines_num=[0 for _ in range(n+1)]
        pre=[(-1) for _ in range(n+1)]
        edge_list=list()
        for x,y in edges:
            edge_list.append(Edge(y))
            addEdge(x,y)
            edge_list.append(Edge(x))
            addEdge(y,x)
        used=[False for _ in range(m)]
        ans_normal,ans_singlar=0,0
        flag=0
        end_set=set()
        temp_second=-1
        for i in range(1,n+1):
            dsf(i,-1)
        return ans_singlar*2+ans_normal

方法二:遍历中间路径法

在这里插入图片描述

1.思路

没有办法,第一种的时间复杂度太高了,即使是剪枝仍然解决不了问题。所以换一种思路来看看。我们拿最后一个例子来研究一下:在这里插入图片描述
如图所示为每个顶点的度。我们在方法一中,通过O(n)的时间可以记录这个图的结构,即每个节点它的度是多少,它与哪写节点相邻。于是我们突发奇想,如果我们遍历中间的两个节点试试呢?
比如,节点1和节点2。节点1的度为3,节点2的度为2,二者相交后,节点1剩下的度为3-1=2,节点2剩下的度为2-1=1.所以二者组合后的以1,2为中间两点的组合有2*1*2种,之所以在后面又乘上了一个2,是因为我们可以逆序。。。
就是这个思路,有没有感觉很巧妙~

2.时间复杂度

O(N**2)

3.代码


#方法二,时间复杂度为O(n^2)
class Edge:
    def __init__(self,to=-1):
        self.to=to
        self.source_edge=-1       
class Solution:
    def networkRoads(self,n,m,edges) -> str:
        def addEdge(u,v):
            nonlocal cnt
            nonlocal lines_num
            edge_list[cnt].to=v
            edge_list[cnt].source_edge=pre[u]
            lines_num[u]+=1
            pre[u]=cnt
            cnt+=1
            
        def twoNode(start):
                nonlocal ans
                p=pre[start]
                while p!=-1:                
                    q=edge_list[p].to
                    if q>start:
                        ans+=(lines_num[start]-1)*(lines_num[q]-1)
                    p=edge_list[p].source_edge
        cnt=0
        #lines_num[i]表示第i个点的边的度
        lines_num=[0 for _ in range(n+1)]
        pre=[(-1) for _ in range(n+1)]
        edge_list=list()
        for x,y in edges:
            edge_list.append(Edge(y))
            addEdge(x,y)
            edge_list.append(Edge(x))
            addEdge(y,x)
        ans=0
        for i in range(1,n+1):
            twoNode(i)
        return ans*2




    
if __name__=='__main__':
    solution=Solution
    n,m=map(int,input().split())
    edges=list()
    for i in range(m):
        node1,node2=map(int,input().split())
        edges.append((node1,node2))
##    n,m=3,3
##    edges=[(1,2),(2,3),(1,3)]
##    n,m=4,4
##    edges=[(1,2),(2,3),(3,1),(1,4)]
##    n,m=3,1
##    edges=[(1,3)]
    result=solution.networkRoads(solution,n,m,edges)
    print(result)

总结

这道题目,解题的技巧就在于方法二。当我们一个点一个点的来进行遍历时时间复杂度很高,于是我们就直接遍历中间的路径。对于c++之类的,用方法一可以通过,但是对于python代码来说,就一定要采用花费时间最少的算法。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Wumbuk

您的支持是我坚持的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值