"""W02: shortest paths on a DAG, allowing negative integer edge weights."""fromcollectionsimportdequedefshortest_paths(n,edges,source):iftype(n)isnotintornot1<=n<=10000ortype(source)isnotintornot0<=source<n:raiseValueError("bounded valid vertices required")edges=list(edges)iflen(edges)>100000:raiseValueError("too many edges")adjacent=[[]for_inrange(n)]incoming=[0]*nseen=set()foru,v,winedges:ifany(type(x)isnotintforxin(u,v,w))ornot0<=u<nornot0<=v<n:raiseValueError("valid integer endpoints and weight required")if(u,v)inseen:raiseValueError("parallel edges excluded in this lab")seen.add((u,v));adjacent[u].append((v,w));incoming[v]+=1ready=deque(iforiinrange(n)ifincoming[i]==0)order=[]whileready:u=ready.popleft();order.append(u)forv,_inadjacent[u]:incoming[v]-=1ifincoming[v]==0:ready.append(v)iflen(order)!=n:raiseValueError("graph is not acyclic")distance,previous=[None]*n,[None]*ndistance[source]=0foruinorder:ifdistance[u]isNone:continueforv,winadjacent[u]:candidate=distance[u]+wifdistance[v]isNoneorcandidate<distance[v]:distance[v]=candidate;previous[v]=ureturndistance,previous,orderdefpath(previous,source,target):ifnot0<=source<len(previous)ornot0<=target<len(previous):raiseValueError("invalid endpoint")result=[];seen=set();current=targetwhilecurrentisnotNone:ifcurrentinseen:raiseValueError("invalid cyclic predecessor data")seen.add(current);result.append(current)ifcurrent==source:returnlist(reversed(result))current=previous[current]returnNoneif__name__=='__main__':d,p,order=shortest_paths(4,[(0,1,2),(0,2,5),(2,1,-4),(1,3,2)],0)print(d,order,path(p,0,3))