94. 城市间货物运输 I
思路:今天的题目都是Bellman_ford 算法,思路就是要根据点的数量n来进行n次全部“松弛”(代表最多走n-1条边到达终点),所谓松弛就是在对每一个条边进行计算,判断能否出现更短的路径,主要是为了解决可能出现的负权值情况(这道题没有),所以要不断的重复遍历。而因为每一次遍历的所有edges都是一样的,所以如果一次遍历后没有修改任何值,那以后也不会修改了,可以直接break
n,m=map(int,input().strip().split())
edges=[]
for _ in range(m):
s,t,v=map(int,input().strip().split())
edges.append((s,t,v))
minDist=[float('inf')]*(n+1)
minDist[1]=0
for i in range(1,n):
update=False
for start,end,val in edges:
if minDist[start]!=float('inf') and minDist[start]+val<minDist[end]:
minDist[end]=minDist[start]+val
update=True
if update==False:
break
if minDist[-1]==float('inf'):
print("unconnected")
else:
print(minDist[-1])
之后还有一个队列优化的方法,因为只有被初始化(即赋值不是inf)的才会考虑,所以我们只需要把每一次加入的新节点加入队列就可以了,而当这个节点被使用过后要把visit数组改成false(因为可能需要重复经过这个点。在邻接表的初始化的时候要注意[[] for _ in range(n+1)]而不是[[]*(n+1)]因为这样会导致实际上还是一个[]
from collections import deque
n,m=map(int,input().split())
graph=[[] for _ in range(n+1)]
for _ in range(m):
s,t,v=map(int,input().split())
graph[s].append((t,v))
minDist=[float('inf')]*(n+1)
minDist[1]=0
visit=[False]*(n+1)
visit[1]=True
que=deque([1])
while que:
cur=que.popleft()
visit[cur]=False
for dest,val in graph[cur]:
if minDist[cur]!=float('inf') and minDist[cur]+val<minDist[dest]:
minDist[dest]=minDist[cur]+val
if visit[dest]==False:
visit[dest]=True
que.append(dest)
if minDist[-1]==float('inf'):
print("unconnected")
else:
print(minDist[-1])
95. 城市间货物运输 II
思路:这道题就是会有负权值回路,导致无限循环的话,值会越来越小,为了避免这种情况,所以在最后新加一次计算,如果有改变,那说明存在负回路
n,m=map(int,input().strip().split())
edges=[]
for _ in range(m):
s,t,v=map(int,input().strip().split())
edges.append((s,t,v))
minDist=[float('inf')]*(n+1)
minDist[1]=0
flag=False
for i in range(1,n+1):
for start,end,val in edges:
if i<n:
if minDist[start]!=float('inf') and minDist[start]+val<minDist[end]:
minDist[end]=minDist[start]+val
if i==n:
if minDist[start]!=float('inf') and minDist[start]+val<minDist[end]:
flag=True
if flag==True:
print("circle")
elif minDist[-1]==float('inf'):
print("unconnected")
else:
print(minDist[-1])
96. 城市间货物运输 III
思路:这道题的特别是在最多只能经过k个城市(算上起点和终点一共经过k+1条边),看起来只需要循环限制为k+1次,但实际上并不是,因为每一次的遍历可能会使用在这一轮遍历新修改的值,而不是上一轮修改后的值,导致并不是严格的k+1次,因此每一轮我们都要使用一个副本,复制一下开始时的minDist数组
n,m=map(int,input().split())
edges=[]
for _ in range(m):
s,t,v=map(int,input().split())
edges.append((s,t,v))
src,dst,k=map(int,input().split())
minDist=[float('inf')]*(n+1)
minDist[src]=0
for _ in range(k+1):
update=False
minDist_c=minDist[:]
for start,end,val in edges:
if minDist_c[start]!=float('inf') and minDist_c[start]+val<minDist[end]:
minDist[end]=minDist_c[start]+val
update=True
if not update:
break
if minDist[dst]==float('inf'):
print("unreachable")
else:
print(minDist[dst])

328

被折叠的 条评论
为什么被折叠?



