# Shortest Path

## Floyd Warshall

[Link](http://wiki.jikexueyuan.com/project/easy-learn-algorithm/floyd.html)

* 尋找點對點之間的最短距離
* 更新v次edge的情況
* Time O(n^3)

```java
package graph;
import com.sun.tools.doclets.formats.html.SourceToHTMLConverter;

import java.util.*;

public class floyd_warshall {
    private void fw(int v, int[][] edges){
        int inf = (int)1e8;

        // init distance matrix
        int[][] matrix = new int[v][v];
        for(int i=0; i<v; i++){
            for(int j=0; j<v; j++){
                if(i==j) matrix[i][j]=0;
                else matrix[i][j] = inf;
            }
        }

        // read the edge to matrix
        for(int[] e: edges){
            matrix[e[0]][e[1]] = e[2];
        }

        // Floyd Warshall Algo
        for(int k=0; k<v; k++){
            for(int i=0; i<v; i++){
                for(int j=0; j<v; j++){
                    if(matrix[i][j] > matrix[i][k] + matrix[k][j]){
                        matrix[i][j] = matrix[i][k] + matrix[k][j];
                    }
                }
            }
        }

        // print matrix
        StringBuilder sb = new StringBuilder();
        for(int[] row: matrix){
            for(int n: row){
                sb.append(n).append(",");
            }
            sb.append("\n");
        }

        System.out.println(sb.toString());
    }

    public static void main(String[] args) {
        floyd_warshall f = new floyd_warshall();
        int[][] e = new int[][]{
                {0,1,2},
                {0,2,6},
                {0,3,4},
                {1,2,3},
                {2,0,7},
                {2,3,1},
                {3,0,5},
                {3,2,12}
        };

        f.fw(4, e);
    }
}
```

## Dijkstra

[Link](http://wiki.jikexueyuan.com/project/easy-learn-algorithm/dijkstra.html)

* Greedy, 每次尋找neighbor dist最短的vertex
* weight不能是負數
* Time O(E + VlogV)
* A visited set, a minHeap<\[node]\[distance to start]>
* Heap會優先更新距離短的，使vertex 更新必定是最短距離&#x20;

```java
package graph;
import java.util.*;

public class dijkstra {
    private void algo(int num, int[][] edges, int start){
        int distance[] = new int[num];

        // int[0] is vertex, int[1] is distance
        Queue<int[]> heap = new PriorityQueue<>((a,b)->a[1]-b[1]);

        // init distance matrix
        int[][] matrix = new int[num][num];

        // read the edge to matrix
        for(int[] e: edges) {
            matrix[e[0]][e[1]] = e[2];
        }

        // init distance[]
        Arrays.fill(distance, Integer.MAX_VALUE);
        distance[start] = 0;

        heap.add(new int[]{start, 0});

        // Dijkstra Algo
        while(!heap.isEmpty()){
            int[] vertex_u = heap.poll();
            int u = vertex_u[0];
            // loop the neighbors

            for(int v=0; v<num; v++){
                if(matrix[u][v] != 0){
                    if(distance[v] > distance[u] + matrix[u][v]){
                        distance[v] = distance[u] + matrix[u][v];
                    }
                    heap.add(new int[]{v, distance[v]});
                }
            }
        }
        // print distance[]
        for(int dist: distance){
            System.out.println(dist);
        }
    }

    public static void main(String[] args) {
        dijkstra d = new dijkstra();
        int[][] edges = new int[][]{
                {0,1,1},
                {0,2,12},
                {1,2,9},
                {1,3,3},
                {2,4,5},
                {3,2,4},
                {3,4,13},
                {3,5,15},
                {4,5,4}
        };
        d.algo(6,edges,0);
        // [0, 1, 8, 4, 13, 17]
    }
}
```

## 787. Cheapest Flights Within K Stops

There are n cities connected by m flights. Each fight starts from city u and arrives at v with a price w.

Now given all the cities and fights, together with starting city src and the destination dst, your task is to find the cheapest price from src to dst with up to k stops. If there is no such route, output -1.

* maintain cost and stop array
* 遇到 dst 即退出
* 遇到 stop >= K+1 即拋棄 continue
* update cost\[v] if curCost + matrix\[u]\[v] is less
* update stop\[v] if stop+1 is less
* return cost\[v] and check if valid

```java
[[0,1,5],[1,2,5],[0,3,2],[3,1,2],[1,4,1],[4,2,1]]
0
2
2
answer = 7
```

```java
public int findCheapestPrice(int n, int[][] flights, int src, int dst, int K) {
    int[][] matrix = new int[n][n];

    // init matrix
    for(int[] flight: flights){
        matrix[flight[0]][flight[1]] = flight[2];
    }

    // init cost[]
    int[] costs = new int[n];
    Arrays.fill(costs, Integer.MAX_VALUE);
    costs[src] = 0;

    // init stop[]
    int[] stops = new int[n];
    Arrays.fill(stops, Integer.MAX_VALUE);

    // int[0]=vertex, int[1]=number of stops, int[2]=cost 
    Queue<int[]> heap = new PriorityQueue<>((a,b) -> a[2] - b[2]);
    heap.add(new int[]{src, 0, 0});

    while(!heap.isEmpty()){
        int[] cur = heap.poll();
        int u = cur[0], curStop = cur[1], curCost= cur[2];
        if(u == dst) return curCost;
        if(curStop == K+1) continue;
        for(int v=0; v<n; v++){
            if(matrix[u][v] != 0){
                int newCost = curCost+matrix[u][v];
                int newStop = curStop+1;
                // 更新到 v 點的 lowest cost
                if(costs[v] > newCost){
                    heap.add(new int[]{v, newStop, newCost});
                    costs[v] = newCost;
                } 
                // 加上雖然cost較大，但轉機次數較少的vertax
                else if(stops[v] > newStop){
                    heap.add(new int[]{v, newStop, newCost});
                    stops[v] = newStop;
                }
            }
        }
    }
    return costs[dst]==Integer.MAX_VALUE ? -1: costs[dst];
}
```

## 1102. Path With Maximum Minimum Value

Given a matrix of integers `A` with R rows and C columns, find the **maximum** score of a path starting at `[0,0]` and ending at `[R-1,C-1]`.

The _score_ of a path is the **minimum** value in that path.  For example, the value of the path 8 →  4 →  5 →  9 is 4.

[Explain](https://leetcode.com/problems/path-with-maximum-minimum-value/discuss/416227/Python-Dijkstra-Binary-Search-%2B-DFS-Union-Find-complexity-analysis)

1. Local Greedy, 從四個方向找到 local min然後從maxHeap選擇max延伸

```python
def maximumMinimumPath(self, A: List[List[int]]) -> int:
    m, n = len(A), len(A[0])
    seen = set()
    maxHeap = [(-A[0][0], 0, 0)]
    heapify(maxHeap)
    
    while maxHeap:
        val, i, j = heappop(maxHeap)
        if (i, j) == (m-1, n-1): return -val
        # seen.add((i, j)) 在這裡會TLE
        
        for dy, dx in ((0, 1), (1, 0), (0, -1), (-1, 0)):
            y = i + dy
            x = j + dx
            if not (0 <= y < m and 0 <= x < n and (y, x) not in seen): continue
                               # 這邊是要比較cur and new 哪個比較小
            heappush(maxHeap, (max(val, -A[y][x]), y, x))
            seen.add((y ,x)) # 在這會pass
    
    # if A has only 1 element
    return A[0][0]
```

## 778. Swim in Rising Water

```python
Input: [[0,1,2,3,4],[24,23,22,21,5],[12,13,14,15,16],[11,17,18,19,20],[10,9,8,7,6]]
Output: 16
Explanation:
 0  1  2  3  4
24 23 22 21  5
12 13 14 15 16
11 17 18 19 20
10  9  8  7  6

The final route is marked in bold.
We need to wait until time 16 so that (0, 0) and (4, 4) are connected.
```

```python
"""
Dijkstra: 每次尋找regional min
並且紀錄路線中出現的max
"""
from heapq import *
class Solution:
    def swimInWater(self, grid: List[List[int]]) -> int:
        n = len(grid)
        heap = [(grid[0][0], 0, 0)]
        
        max_t = 0
        seen = set()
        
        while heap:
            val, i, j = heappop(heap)
            max_t = max(max_t, val)
            if (i, j) == (n-1, n-1): return max_t
            for dy, dx in ((0,1), (1,0), (0,-1), (-1,0)):
                y = i + dy
                x = j + dx
                if not(0<=y<n and 0<=x<n and (y,x) not in seen): continue
                heappush(heap, (grid[y][x], y, x))
                seen.add((y, x))
```
