1. 程式人生 > 實用技巧 >python 最短路徑

python 最短路徑

賈格爾(Jagger)找到一張地圖,該地圖指示大量寶藏的位置,並希望找到它們。
該地圖將幾個位置標記為節點和幾個邊緣,這表示兩個位置直接相連。 總共有n個節點和m個邊。 賈格爾(Jagger)位於節點1,寶物位於節點n。
當他執行最短路徑演算法以找出通往寶藏的最短路徑時,他突然發現除了他的起始節點和寶藏的位置以外,每個節點都有一個怪物。 節點u上的怪物具有力量su。 賈格爾的力量為x。 當且僅當x≥su時,Jagger才能通過節點u。
Jagger現在想知道最小x是多少,以便他可以找到從1到n的路徑。

Jagger finds a map that indicates the location of a large number of
treasure and would like to find them.
The map marks several locations as nodes and several edges which indicates
that two locations are connected directly. There are n nodes and m edges in
total. Jagger is located at node 1 and the treasure is located at node n.
When he is running shortest path algorithm in his head to find out the
shortest path to the treasure, he suddenly finds out that every node has a
monster except his starting node and the location of the treasure. A monster at
node u has strength su. Jagger has strength x. Jagger can pass node u if and
only if x su.
Jagger is now wondering what’s the minimum x so that he can find a path
to from 1 to n.

Input
For this problem there are multiple test cases. The first line contains a single
integer T (1 T 100000) indicates the number of test cases. You are
suggested to write a loop to deal with different test cases.
Each test case consists of multiple lines. For each test case:
The first line contains two integer n(1 n 20000) and m(1 m 20000).
The second line contains n integer si(0 si106; s1 = 0; sn = 0) where si is
the strength of the monster at node i for 2 i n - 1.
Each of the next m lines contains two integers ui; vi(1 ui; vin) indicates that there is an edge between ui and vi.
Remark:
• The graph is connected for each testcase.
• It is guaranteed that the sum of all n among the test cases is smaller
than or equal to 105 and the sum of all m among the test cases is smaller
than or equal to 2 × 105.
• There may be multiple edges between same pair of nodes.
• There may be self-loop edges where two end of edge are same.
Output


Output minimum x so that there is path from 1 to n for Jagger.
Sample Input 1
2
2 1
0 0
1 2
4 4
0 50 100 0
1 2
1 3
2 4
3 4
Sample Output 1
0
50
Sample Input 2
4
6 12
0 6 7 4 10 0
6 4
1 3
3 6
5 3
1 2
2 2
6 2
1 6
1 3
6 5
1 4
1 4
7 8
0 8 7 7 3 3 0
7 3
3 5
1 5
5 2
3 5
6 7
4 7
1 6
6 13
0 7 3 4 9 0
3 1
2 4
6 1
5 6
5 1
4 2
3 1
6 1
1 4
1 2
3 6
3 6
3 5
10 9
0 6 7 8 5 5 8 8 4 0
8 4
6 8
8 5
1 2
6 9
8 2
10 9
3 8
7 3
Sample Output 2

0

3

0

8

思路:其實就是迪傑斯特拉的應用,只是稍微需要修改一下更新條件,即該點(u)能不能加入集合需要滿足:x >= s[u]。

def djst(sour, cost, n, m, s, x):
    distance = [99999999] + [cost[sour][i] for i in range(1, n+1)]
    distance[sour] = 0
    used = [False for _ in range(1+n)]
    used[sour] = True
    # print(distance)
    max_x = max(s) + 1
    # x = 8
    # while x <= max_x:
    while True:
        v = -1
        # 從未使用過的頂點中選擇一個距離最小的頂點
        for u in range(1, 1+n): # x >= s[u] and
            if x >= s[u] and not used[u] and (v == -1 or distance[u] < distance[v]):
                # print(u)
                v = u
        if v == -1:
            break
        # 將選定的頂點加入到S中, 同時進行距離更新
        used[v] = True
        # 更新U中各個頂點到起點s的距離。之所以更新U中頂點的距離,是由於上一步中確定了k是求出最短路徑的頂點,從而可以利用k來更新其它頂點的距離;例如,(s,v)的距離可能大於(s,k)+(k,v)的距離。
        for u in range(1, 1+n):
            if x >= s[u]:
                distance[u] = min(distance[u], distance[v] + cost[v][u])
    if distance[n] != 99999999:
        return True
    else:
        return False

t = eval(input())
for i in range(t): # 樣例數量
    x = list(map(int, input().split()))
    n, m = x[0], x[1]  # 獲取節點數量和邊數
    s = list(map(int, input().split())) # 讀入怪物限制
    cost = [[99999999] * (n+1) for i in range(n+1)] # 初始化每個點間的距離
    for j in range(m): # 讀邊
        temp = list(map(int, input().split()))
        a, b = temp[0], temp[1]
        # print(a, b)
        cost[a][b] = cost[b][a] = 0
    # print(cost)
    s = [0] + s
    max_x = max(s) + 1
    for x in range(max_x+1):
        r = djst(1, cost, n, m, s, x)
        if r:
            print(x)
            break