深度优先搜索-Roads
N个城市,编号1到N。城市间有R条单向道路。
每条道路连接两个城市,有长度和过路费两个属性。
Bob只有K块钱,他想从城市1走到城市N。问最短共需要走多长的路。
如果到不了N,输出-1
2<=N<=100
0<=K<=10000
1<=R<=10000
每条路的长度 L, 1 <= L <= 100,每条路的过路费T , 0 <= T <= 100
输入:
K N R s1
e1 L1 T1
s1 e2 L2 T2
...
sR eR LR TR
s e是路起点和终点
解题思路:从城市 1开始深度优先遍历整个图,找到所有能过到达 N 的走法,
选一个最优的。
最优性剪枝:
1) 如果当前已经找到的最优路径长度为L ,那么在继续搜索的过程中,总长度已经大于
等于L的走法,就可以直接放弃,不用走到底了
保存中间计算结果用于最优性剪枝:
2) 用midL[k][m] 表示:走到城市k时总过路费为m的条件下,最优路径的长度。若在
后续的搜索中,再次走到k时,如果总路费恰好为m,且此时的路径长度已经超过
midL[k][m],则不必再走下去了。
输入:
5
6
7
1 2 2 3
2 4 3 3
3 4 2 4
1 3 4 1
4 6 2 1
3 5 2 0
5 4 3 2
输出:
11
python算法实现:
1 INF = float("inf") 2 # k-钱,N-终点,R-共有多少条边 3 K, N, R = 0, 0, 0 4 # 当前找到的最优路径的长度 5 minLen = INF 6 # 正在走的路径的长度、正在走的路径的花销 7 totalLen, totalCost = 0, 0 8 # 城市是否已经走过的标记 9 visited = [] 10 nodeList = list() 11 # minL[i][j]表示从1到i点的,花销为j的最短路的长度 12 minL = [[INF for cols in range(10100)] for rows in range(110)] 13 14 # 存储邻接表的class结构 15 class Node(): 16 def __init__(self, code, data=None, bnext=None): 17 self.code = code 18 self.data = dict() 19 self.bnext = list() 20 21 22 # 从s点开始向N行走 23 def dfs(s): 24 global K, N, minLen, totalLen, totalCost, nodeList, minL 25 # 说明走到终点 26 if s == N: 27 minLen = min(minLen, totalLen) 28 return 29 #对s有多少条可以走出去的边进行遍历 30 # 获取list中s与code相等的索引位置 31 index = 0 32 # 在nodeList列表中找s起始点的索引位置 33 for i, item in enumerate(nodeList): 34 if s == item.code: 35 index = i 36 break 37 # 对起始点的所有的相邻点都进行遍历 38 for i, item in enumerate(nodeList[index].bnext): 39 # 走当前点的费用大于手里有的总金额,不能走,遍历下一条路 40 # 也就是钱不够用了,data是字典,key-顶点,value-列表,索引0:长度,索引1:花费金额 41 if totalCost + nodeList[index].data.get(item)[1] > K: 42 continue 43 # 如果该点没有访问过 44 if visited[item] == 0: 45 # 如果totalLen+当前点的路径长度大于之前的最优路径长度,说明不是 46 # 最优的路径,所以之后的路不需要再递归走了 47 if totalLen + nodeList[index].data.get(item)[0] >= minLen: 48 continue 49 # 如果走到当前节点花费的价钱相同,如果路径更长的话,则不继续往下走 50 # 第2种最优性剪枝 51 if totalLen + nodeList[index].data.get(item)[0] > minL[item][totalCost + nodeList[index].data.get(item)[1]]: 52 continue 53 minL[item][totalCost + nodeList[index].data.get(item)[1]] = totalLen + nodeList[index].data.get(item)[0] 54 totalLen += nodeList[index].data.get(item)[0] 55 totalCost += nodeList[index].data.get(item)[1] 56 visited[item] = 1 57 dfs(item) 58 # 本条路线走完该点后,需要重新把点的标记、长度和花费都重置, 59 # 因为下次新的路线可能还会走该点 60 visited[item] = 0 61 totalLen -= nodeList[index].data.get(item)[0] 62 totalCost -= nodeList[index].data.get(item)[1] 63 return 0 64 65 66 def main(): 67 global K, N, R, visited, minLen, nodeList 68 K, N, R = map(int, input().split()) 69 visited = [0 for i in range(N+1)] 70 # 构造邻接表 71 for i in range(R): 72 s, t, l, c = map(int, input().split()) 73 in_flag = False 74 tempNode = Node(s) 75 tempNode.bnext.append(t) 76 tempNode.data.update({t: [l, c]}) 77 if len(nodeList) > 0: 78 for j in nodeList: 79 if s == j.code: 80 in_flag = True 81 break 82 if in_flag: 83 j.bnext.append(t) 84 j.data.update({t: [l, c]}) 85 else: 86 nodeList.append(tempNode) 87 else: 88 nodeList.append(tempNode) 89 tempNode = Node(0) 90 tempNode.bnext.append(0) 91 tempNode.data.update({0: [0, 0]}) 92 nodeList.insert(0, tempNode) 93 # 因为从1号点开始,所以先把1号点标志已走过 94 visited[1] = 1 95 # 从1号点开始深度搜索 96 dfs(1) 97 # 如果minLen小于无穷大,说明找到了最优的路径,否则输出-1 98 if minLen < float("inf"): 99 print(minLen) 100 else: 101 print(-1) 102 return 0 103 104 105 if __name__ == '__main__': 106 main()