相对论大师-记录型正负性质BFS/图论-链表/数据结构

看到这一题我的第一个思路就是双向bfs

起点是a,终点还是a,但是flag是相反的("越"的方向)

tip1.可以用字典vis来存储flag

刚开始初始化时vissta,visend一个对应0、1

要求两个队列相接的时候flag要相同

tip2.get_nei函数

读取输入的时候用字典存储了点之间的关系

那么get_nei的时候就需要返回可能的下个节点以及new_flag

new_flag还是在bfs中判断,因为读取输入的时候是用0表示同向,1表示反向

tip3.存储中间过程

由于触碰点是起点和终点中间,所以我们需要记录前驱节点从而进行回溯

那么最适合的就是链表

python 复制代码
from collections import deque,defaultdict

d=defaultdict(set)

n=int(input())

for i in range(n):
    a,n1,b,n2=input().split()
    if n1==n2:
        d[a].add((b,0))
        #明显不能双向:否则会Yu 1 Yuci 0 Yuci 0 Yu 0 = Yu 1 Yu 0
        #d[b].add((a,0))#双向图?
        
    else:
        d[a].add((b,1))
        
        #d[b].add((a,1))
        
     
def get_nei(cur):
    neis=d[cur]
    return neis


def bfs(k):
    sta=end=k
    staq=deque([sta])
    endq=deque([end])
    vissta={sta:1}#用0,1表示相对性
    visend={end:0}


    presta={sta:None}#记录前驱节点
    preend={end:None}
    
    while staq and endq:
        ls=len(staq)
        le=len(endq)
        if ls<=le:
            for _ in range(ls):#当前层
                cur=staq.popleft()
                flag=vissta[cur]
                for nei,k in get_nei(cur): #解包
                    if k:
                        nflag= flag #0,1间取反
                    else:
                        nflag=not flag
                    if nei not in vissta:
                        vissta[nei]=nflag
                        staq.append(nei)

                        presta[nei]=cur
                        
                        if nei in visend and visend[nei]==vissta[nei]:
                            return build_path(nei,presta,preend)
        else:
            for _ in range(le):
                cur=endq.popleft()
                flag=visend[cur]
                for nei,k in get_nei(cur):
                    if k:
                        nflag=not flag #0,1间取反
                    else:
                        nflag=flag
                    if nei not in visend:
                        visend[nei]=nflag
                        endq.append(nei)

                        preend[nei]=cur
                        
                        if nei in vissta and vissta[nei]==visend[nei]:
                            return build_path(nei,presta,preend)
    return 0


def build_path(meet,presta,preend):
    path_sta=[]
    cur=meet
    while cur is not None:#开始链表回溯
        path_sta.append(cur)
        cur=presta[cur]
    path_sta.reverse()#掉头,方面后面衔接

    path_end=[]
    cur=preend[meet]
    while cur is not None:
        path_end.append(cur)
        cur=preend[cur]

    return path_sta+path_end

print(d)

for i in d:
    k=bfs(i)
    print(k)


'''不能dfs:不知道何时停止
def dfs()
'''

但是这段代码其实是错的

因为d[x]存的是x后面的节点,是单向的

所以无法从d[x]得到从终点返回的节点,只有d[k]=x遍历字典才能得到k,那还不如单向bfs

python 复制代码
from collections import deque
from collections import defaultdict

d = defaultdict(list)

n = int(input())
for _ in range(n):
    a, a_flag, b, b_flag = input().split()
    a_flag = int(a_flag)
    b_flag = int(b_flag)
    d[(a, a_flag)].append((b, b_flag))

shortest_path = None

nodes = set()
for key in d:
    nodes.add(key[0])
    for b, _ in d[key]:
        nodes.add(b)
nodes = list(nodes)

for sta in nodes:
    for start_flag in [0, 1]:
        target_flag = 1 - start_flag
        vissta = {}
        staq = deque()

        staq.append((sta, start_flag, []))
        vissta[(sta, start_flag)] = True
        found = False
        while staq and not found:
            cur, flag, path_edges = staq.popleft()
          
            if cur == sta and flag == target_flag:
                if shortest_path is None or len(path_edges) < len(shortest_path):
                    shortest_path = path_edges
                found = True
                break

            for (nei, nei_flag) in d.get((cur, flag), []):
                if (nei, nei_flag) not in vissta:
                    vissta[(nei, nei_flag)] = True
                    new_path = path_edges + \
                        [(cur, flag, nei, nei_flag)]
                    staq.append((nei, nei_flag, new_path))
        if found and len(shortest_path) == 0:
            break 
    if shortest_path and len(shortest_path) == 0:
        break 

output_steps = []
for step in shortest_path:
    a, a_flag, b, b_flag = step
    output_steps.append(f"{a} {a_flag} {b} {b_flag}")

sta = shortest_path[0][0]
start_flag = shortest_path[0][1]
end_flag = 1 - start_flag

print(f"{' '.join(output_steps)} = {sta} {start_flag} {sta} {end_flag}")
相关推荐
PythonicCC12 分钟前
基于Python Socket的多线程聊天程序案例分析
python
天天扭码13 分钟前
一分钟解决 | 高频面试算法题——滑动窗口最大值(单调队列)
前端·算法·面试
Dxy123931021629 分钟前
NLTK 语料库与词典资源
python
tan77º35 分钟前
【算法】BFS-解决FloodFill问题
算法·leetcode·宽度优先
知识烤冷面37 分钟前
【力扣刷题实战】找到字符串中所有字母异位词
数据结构·算法·leetcode
站大爷IP38 分钟前
Python中main函数:代码结构的基石
python
XiaoyaoCarter1 小时前
每日两道leetcode
c++·算法·leetcode·职场和发展·贪心算法
爱心发电丶1 小时前
WePush 一款基于模拟点击实现的微信消息推送机器人,安全稳定不封号
python
青瓦梦滋1 小时前
【算法】双指针8道速通(C++)
数据结构·算法·leetcode
程序员-King.1 小时前
day48—双指针-通过删除字母匹配到字典最长单词(LeetCode-524)
算法·leetcode·双指针