1. 单源最短路
1.1 无负权边 - 迪杰斯特拉算法
- 自环和重边对迪杰斯特拉算法没有影响。
- 要求无负权边的原因是:考虑自环中有负权边的情况
其中A 为源点,C为终点,第一轮选取源点A,结束后更新,d[c]=1,d[b]=2,第二轮选取C点,不再更新d[c],d[c]值固定为1,但实际上A到C的最短距离应该为2+(-2)=0。
算法核心:每次选取距离源点最近的点,对其余距离进行刷新,直至选取到目标点。
def djs():
global n,m,hd,va,nx,wg
M=0x3f3f3f
st=[True]*(n+1)
d=[M]*(n+1)
d[1]=0
for i in range(n):
id=-1
tmp=M
for t in range(1,n+1):
if st[t] and tmp>d[t]:
tmp=d[t]
id=t
st[id]=False
j=hd[id]
while j!=-1:
d[va[j]]=min(d[id]+wg[j],d[va[j]])
j=nx[j]
if d[n]<M:
print(d[n])
else:
print(-1)
n,m=map(int,input().split())
hd=[-1]*(n+1)
va=[0]*(m+1)
nx=[-1]*(m+1)
wg=[0]*(m+1)
idx=0
for _ in range(m):
x,y,z=map(int,input().split())
va[idx]=y
nx[idx]=hd[x]
hd[x]=idx
wg[idx]=z
idx+=1
djs()
1.2 有负权边
1.2.1 限制经过边数≤k - bellman算法
- 图中可以存在负权回路,因为已有k对循环次数进行限制。
算法核心:用刷新次数为k限制经过边数,每次刷新扫描所有边,更新d[]。
def bellman():
global n,m,k,edge,M,d
for i in range(k):
import copy
tmp=copy.deepcopy(d)
for t in edge:
x,y,z=t
d[y]=min(tmp[x]+z,d[y])
if d[n]<M/2:
print(d[n])
else:
print("impossible")
n,m,k=map(int,input().split())
edge=[]
for _ in range(m):
edge.append(list(map(int,input().split())))
M=2*(10**8)+1
d=[M]*(n+1)
d[1]=0
bellman()
1.2.2 不限制经过边数 - spfa算法
- 图中可以有负权边,但不可以有负权回路。
- 可以用spfa算法判断图中是否包含负环,只需要加一个cnt用以计数即可 (判断条件≥n)。
可以看成解禁版迪杰斯特拉算法。
def spfa():
global n,m,hd,va,nx,wg
M=2*(10**9)+1
d=[M]*(n+1)
d[1]=0
q=[0]*(10**5+1)
st=[True]*(n+1)
hh=tt=0
q[tt]=1
st[1]=False
tt+=1
while tt-hh>0:
tmp=q[hh]
hh+=1
st[tmp]=True
j=hd[tmp]
while j!=-1:
if d[va[j]]>d[tmp]+wg[j]:
d[va[j]]=d[tmp]+wg[j]
if st[va[j]]:
st[va[j]]=False
q[tt]=va[j]
tt+=1
j=nx[j]
if d[n]<M/2:
print(d[n])
else:
print("impossible")
n,m=map(int,input().split())
hd=[-1]*(n+1)
va=[0]*(m+1)
nx=[-1]*(m+1)
wg=[0]*(m+1)
idx=0
for _ in range(m):
x,y,z=map(int,input().split())
va[idx]=y
nx[idx]=hd[x]
hd[x]=idx
wg[idx]=z
idx+=1
spfa()
2.多源最短路-弗洛伊德算法
- 图中可能存在重边和自环,边权可能为负数。
- 图中不能存在负权回路。
算法核心:以每一个点当做中介点,更新距离。
M=0x3f3f3f
n,m,k=map(int,input().split())
e=[[M]*(n+1) for _ in range(n+1)]
for i in range(n+1):
e[i][i]=0
for _ in range(m):
x,y,z=map(int,input().split())
e[x][y]=min(e[x][y],z)
for i in range(1,n+1):
print(i," as medium:")
for j in range(1,n+1):
for t in range(1,n+1):
print("update e[",j,"][",t,"]",end='')
if e[j][t]>e[j][i]+e[i][t]:
e[j][t]=e[j][i]+e[i][t]
print("=",e[j][t])
for _ in range(k):
x,y=map(int,input().split())
if e[x][y]<M/2:
print(e[x][y])
else:
print("impossible")