LC-1334. The city with the fewest neighbors within the threshold distance (Floyd algorithm, memorized search ==> dynamic programming (0x3f))

1334. The city with the fewest neighbors within the threshold distance

medium

There are n cities, numbered from 0 to n-1. Give you an edge array edges, where edges[i] = [fromi, toi, weighti] represents fromi and toi code> A bidirectional weighted edge between two cities, the distance threshold is an integer distanceThreshold.

Returns the city with the smallest number of other cities that can be reached through some path and the path distance maximum is distanceThreshold. If there are multiple such cities, the city with the highest number is returned.

Note that the distance of a path connecting cities i and j is equal to the sum of the weights of all edges along the path .

Example 1:

img

Input: n = 4, edges = [[0,1,3],[1,2,1],[1,3,4],[2,3,1]], distanceThreshold = 4
Output: 3
Explanation: The city distribution map is as above.
The neighbor cities within the threshold distance of each city distanceThreshold = 4 are:
city 0 -> [city 1, city 2]
City 1 -> [City 0, City 2, City 3]
City 2 -> [City 0, City 1, City 3]
City 3 -> [City 1, City 2]
Both cities 0 and 3 have 2 neighbor cities within a threshold distance of 4, but we have to return city 3 because it has the highest number.

Example 2:

img

Input: n = 5, edges = [[0,1,2],[0,4,8],[1,2,3],[1,4,2],[2,3,1 ],[3,4,1]], distanceThreshold = 2
Output: 0
Explanation: The city distribution map is as above.
The neighboring cities within the threshold distance distanceThreshold = 2 of each city are:
city 0 -> [city 1]
City 1 -> [City 0, City 4]
City 2 -> [City 3, City 4]
City 3 -> [City 2, City 4]
City 4 -> [City 1, City 2, City 3]
City 0 has only 1 neighbor city within a threshold distance of 2.

Tip:

  • 2 <= n <= 100
  • 1 <= edges.length <= n * (n - 1) / 2
  • edges[i].length == 3
  • 0 <= fromi < toi < n
  • 1 <= weighti, distanceThreshold <= 10^4
  • All (fromi, toi) are different.

Memory search (0x3f)

https://leetcode.cn/problems/find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance/solutions/2525946/dai-ni-fa-ming-floyd- suan-fa-cong-ji-yi-m8s51/?envType=daily-question &envId=2023-11-14

Interpretation of the question: For city i, find the shortest path length from i to other cities, and count how many shortest path lengths there are <= distanceThreshold

Inspiring thoughts:

class Solution {<!-- -->
    public int findTheCity(int n, int[][] edges, int distanceThreshold) {<!-- -->
        int[][] w = new int[n][n];
        for(int[] row : w)
            Arrays.fill(row, Integer.MAX_VALUE / 2);
        for(int[] e : edges){<!-- -->
            int x = e[0], y = e[1], wt = e[2];
            w[x][y] = w[y][x] = wt;
        }
        int[][][] memo = new int[n][n][n];

        int ans = 0;
        int minCnt = n;
        for(int i = 0; i < n; i + + ){<!-- -->
            int cnt = 0;
            for(int j = 0; j < n; j + + ){<!-- -->
                if(j != i & amp; & amp; dfs(n-1, i, j, memo, w) <= distanceThreshold){<!-- -->
                    cnt + + ;
                }
            }
            if(cnt <= minCnt){<!-- --> // When equal, take the largest i
                minCnt = cnt;
                ans = i;
            }
        }
        return ans;
    }

    /**
    Define dfs(k, i, j) to represent the length of the shortest path from i to j, and the intermediate node numbers of this shortest path are all <= k
                    Note that the intermediate node does not contain i and j
    transfer
    If k is not selected, then the numbers of the intermediate nodes are <= k-1, that is, dfs(k, i, j) = dfs(k-1, i, j)
    Choose k, then the problem is decomposed into the shortest path from i to k, and the shortest path from k to j, since the intermediate nodes of these two shortest paths do not include k
            All intermediate node labels are <= k-1, that is, dfs(k, i, j) = dfs(k-1, i, k) + dfs(k-1, k, k)
        In these two cases, take the minimum value
    Recursion boundary dfs(-1, i, j) = w[i][j], k=-1 means there is no intermediate node between i and j, and the shortest path length can only be the edge weight of i and j
                                        If there is no edge connecting i and j, then w[i][j] = ∞
    The recursive entry dfs(n-1, i, j) represents the shortest path length from i to j, k=n-1 is because the node numbers in this question are 0 to n-1
     */
    public int dfs(int k, int i, int j, int[][][] memo, int[][] w){<!-- -->
        if(k < 0)
            return w[i][j];
        if(memo[k][i][j] != 0)
            return memo[k][i][j];
        return memo[k][i][j] = Math.min(dfs(k-1, i, j, memo, w),
                                dfs(k-1, i, k, memo, w) + dfs(k-1, k, j, memo, w));
    }
}

Retweet

Question: Why must k be enumerated at the outermost level?

Answer: Look carefully at the state transition equation above. To correctly calculate f[k + 1][i][j], you must first convert f[k][i][j] , f[k][i][k] and f[k][k][j] are calculated. Since we don’t know the size relationship between k and i,j, only by placing k in the outermost enumeration can we ensure that f[k][i][j], f[k][i][k] and f[k][k][j] Figure it out. By the way, for i and j, when calculating f[k + 1][i][j], f[k][.][.] has been fully calculated, so i and j can be enumerated in forward/reverse order.

class Solution {<!-- -->
    /**
    Bit 0 represents the case of k=-1
    f[k + 1][i][j] = Math.min(f[k][i][j], f[k][i][k] + f[k][k][j])
    Initialization f[0][i][j] = w[i][j]
     */
    public int findTheCity(int n, int[][] edges, int distanceThreshold) {<!-- -->
        int[][] w = new int[n][n];
        for(int[] row : w)
            Arrays.fill(row, Integer.MAX_VALUE / 2);
        for(int[] e : edges){<!-- -->
            int x = e[0], y = e[1], wt = e[2];
            w[x][y] = w[y][x] = wt;
        }
        int[][][] f = new int[n + 1][n][n];
        f[0] = w;
        for(int k = 0; k < n; k + + ){<!-- -->
            for(int i = 0; i < n; i + + ){<!-- -->
                for(int j = 0; j < n; j + + ){<!-- -->
                    f[k + 1][i][j] = Math.min(f[k][i][j], f[k][i][k] + f[k][k][j]) ;
                }
            }
        }
        int ans = 0;
        int minCnt = n;
        for(int i = 0; i < n; i + + ){<!-- -->
            int cnt = 0;
            for(int j = 0; j < n; j + + ){<!-- -->
                if(j != i & amp; & amp; f[n][i][j] <= distanceThreshold){<!-- -->
                    cnt + + ;
                }
            }
            if(cnt <= minCnt){<!-- --> // When equal, take the largest i
                minCnt = cnt;
                ans = i;
            }
        }
        return ans;

    }
}

Status optimization

class Solution {<!-- -->
    /**
    When calculating f[k + 1], only f[k] will be used
    f[k + 1][i][k] represents the length of the shortest path from i to k, and the intermediate node numbers of this shortest path are all <= k
            Since the end point is k, the intermediate nodes must not contain k, so the intermediate node numbers are <= k-1
    ==> f[k + 1][i][k] = f[k][i][k]
    In the same way, f[k + 1][k][j] = f[k][k][j]
     */
    public int findTheCity(int n, int[][] edges, int distanceThreshold) {<!-- -->
        int[][] w = new int[n][n];
        for(int[] row : w)
            Arrays.fill(row, Integer.MAX_VALUE / 2);
        for(int[] e : edges){<!-- -->
            int x = e[0], y = e[1], wt = e[2];
            w[x][y] = w[y][x] = wt;
        }
        int[][] f = new int[n][n];
        f = w;
        for(int k = 0; k < n; k + + ){<!-- -->
            for(int i = 0; i < n; i + + ){<!-- -->
                for(int j = 0; j < n; j + + ){<!-- -->
                    f[i][j] = Math.min(f[i][j], f[i][k] + f[k][j]);
                }
            }
        }
        int ans = 0;
        int minCnt = n;
        for(int i = 0; i < n; i + + ){<!-- -->
            int cnt = 0;
            for(int j = 0; j < n; j + + ){<!-- -->
                if(j != i & amp; & amp; f[i][j] <= distanceThreshold){<!-- -->
                    cnt + + ;
                }
            }
            if(cnt <= minCnt){<!-- --> // When equal, take the largest i
                minCnt = cnt;
                ans = i;
            }
        }
        return ans;

    }
}