目录链接:搜索与图论
743. 网络延迟时间
图之网络延迟时间[Samoyed]
方法1:优先队列BFS
public int networkDelayTime(int[][] times, int N, int K) {
//建图,key是当前节点的 value的0 只是其邻居节点,1 是距离 即u->v 花费w
Map<Integer, Map<Integer, Integer>> graph = new HashMap<>();
for (int[] t : times) {
graph.putIfAbsent(t[0], new HashMap<>());
graph.get(t[0]).put(t[1], t[2]);
}
//采用优先队列存储, 0指的是当前走的距离,1指的是走到当前的节点Node 按距离从小到大排序,这个很关键
Queue<int[]> pq = new PriorityQueue<>((a, b) -> (a[0] - b[0]));
pq.offer(new int[]{0, K});//起始从K 节点开始,走到K节点花了0的距离
boolean[] visited = new boolean[N + 1]; //下标从1开始,多放一个
int ans = 0;//结果集
while (!pq.isEmpty()) {
int[] curr = pq.poll();
//0 是走到当前节点的距离 1 是
int currNode = curr[1], currDist = curr[0];
if (visited[currNode]) continue;//当前点如果访问过,不需要再访问其邻居节点
visited[currNode] = true;
ans = currDist;
N--;//所有的节点被遍历完,可以提前结束
if (N == 0) return ans;
if (graph.containsKey(currNode)) {//访问邻居节点,并更新当前的dist距离
for (int next : graph.get(currNode).keySet()) {
pq.offer(new int[]{currDist + graph.get(currNode).get(next), next});
}
}
}
return N == 0 ? ans : -1;
}
方法2:普通队列BFS
public int networkDelayTime(int[][] times, int N, int K) {
int INF = Integer.MAX_VALUE / 2;
//构建graph
Map<Integer, Map<Integer, Integer>> graph = new HashMap<>();
for (int[] t : times) {
graph.putIfAbsent(t[0], new HashMap<>());
graph.get(t[0]).put(t[1], t[2]);
}
int[] dist = new int[N + 1];
Arrays.fill(dist, INF);//需要初始化成INF,防止溢出,取INF/2
Queue<Integer> q = new LinkedList<>();
q.offer(K);
dist[K] = 0;
while (!q.isEmpty()) {
int u = q.poll();
if (graph.containsKey(u)) {
for (Map.Entry<Integer, Integer> e : graph.get(u).entrySet()) {
int v = e.getKey(), w = e.getValue();
if (dist[u] + w < dist[v]) {//松弛
dist[v] = dist[u] + w;
q.offer(v);
}
}
}
}
int ans = 0;
//跳过0这个不存在的节点
for (int i = 1; i <= N; i++) {
ans = Math.max(ans, dist[i]);
}
return ans == INF ? -1 : ans;
}
方法3:DFS
Map<Integer, Map<Integer, Integer>> graph;
int[] dist;
public int networkDelayTime(int[][] times, int N, int K) {
int INF = Integer.MAX_VALUE / 2;
//构建graph
graph = new HashMap<>();
for (int[] t : times) {
graph.putIfAbsent(t[0], new HashMap<>());
graph.get(t[0]).put(t[1], t[2]);
}
dist = new int[N + 1];
Arrays.fill(dist, INF);//需要初始化成INF,防止溢出,取INF/2
dist[K] = 0;
dfs(K);
int ans = 0;
//跳过0这个不存在的节点
for (int i = 1; i <= N; i++) {
ans = Math.max(ans, dist[i]);
}
return ans == INF ? -1 : ans;
}
private void dfs(int u) {
if (graph.containsKey(u)) {
for (Map.Entry<Integer, Integer> e : graph.get(u).entrySet()) {
int v = e.getKey(), w = e.getValue();
if (dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
dfs(v);
}
}
}
}
方法4:Floyd
public int networkDelayTime(int[][] times, int N, int K) {
int INF = Integer.MAX_VALUE / 2;
int[][] dist = new int[N + 1][N + 1];
for (int i = 0; i <= N; i++) Arrays.fill(dist[i], INF);
for (int[] t : times) {
int u = t[0], v = t[1], w = t[2];
dist[u][v] = w;
}
dist[K][K] = 0;//很关键,一定要初始化
for (int k = 1; k <= N; k++) {
for (int u = 1; u <= N; u++) {
for (int v = 1; v <= N; v++) {
dist[u][v] = Math.min(dist[u][v], dist[u][k] + dist[k][v]);
}
}
}
int ans = -1;
for (int i = 1; i <= N; i++) {
ans = Math.max(ans, dist[K][i]);
}
return ans == INF ? -1 : ans;
}
787. K 站中转内最便宜的航班
方法1:普通队列BFS
public int findCheapestPrice(int N, int[][] flights, int src, int dst, int K) {
//构建图 u->v w
Map<Integer, List<int[]>> graph = new HashMap<>();
for (int[] f : flights) {
graph.putIfAbsent(f[0], new ArrayList<>());
graph.get(f[0]).add(new int[]{f[1], f[2]});
}
Queue<int[]> q = new LinkedList<>();
q.offer(new int[]{src, 0});//0 表示当前点,1表示的是到达当前点的距离dist
int ans = Integer.MAX_VALUE;
int level = 0;
while (!q.isEmpty()) {
int size = q.size();
for (int i = 0; i < size; i++) {
int[] curr = q.poll();
int u = curr[0], dist = curr[1];
if (u == dst) ans = Math.min(ans, dist);//找到目的地站
if (graph.containsKey(u)) {
for (int[] next : graph.get(u)) {
if (dist + next[1] > ans) continue;//松弛
q.offer(new int[]{next[0], dist + next[1]});
}
}
}
//先比较level 与K 再执行++ 的,bfs的层数,类似水波纹的一圈一圈的,一层表示经过一个站
if (level++ > K) break;
}
return ans == Integer.MAX_VALUE ? -1 : ans;
}
方法2:优先队列BFS(Dijkstra)
public int findCheapestPrice(int N, int[][] flights, int src, int dst, int K) {
Map<Integer, Map<Integer, Integer>> graph = new HashMap<>();
for (int[] f : flights) {
graph.putIfAbsent(f[0], new HashMap<>());
graph.get(f[0]).put(f[1], f[2]);
}
Queue<int[]> pq = new PriorityQueue<>((a, b) -> (a[0] - b[0]));
pq.offer(new int[]{0, src, K + 1}); //存的依次是到达当前点v的距离,当前点v,已经经过的站数
while (!pq.isEmpty()) {
int[] curr = pq.poll();
int dist = curr[0], u = curr[1], stops = curr[2];
if (u == dst) return dist;
if (stops > 0) {
if (graph.containsKey(u)) {
for (Map.Entry<Integer, Integer> e : graph.get(u).entrySet()) {
int v = e.getKey(), w = e.getValue();
pq.offer(new int[]{dist + w, v, stops - 1});
}
}
}
}
return -1;
}
方法3:DFS
Map<Integer, List<int[]>> graph;
int ans = Integer.MAX_VALUE;
public int findCheapestPrice(int N, int[][] flights, int src, int dst, int K) {
//构建图 u->v w
graph = new HashMap<>();
for (int[] f : flights) {
graph.putIfAbsent(f[0], new ArrayList<>());
graph.get(f[0]).add(new int[]{f[1], f[2]});
}
dfs(src, dst, K + 1, 0);
return ans == Integer.MAX_VALUE ? -1 : ans;
}
private void dfs(int src, int dst, int K, int dist) {
if (K < 0) return;
if (src == dst) {
ans = dist;
return;
}
if (graph.containsKey(src)) {
for (int[] f : graph.get(src)) {
int u = f[0], w = f[1];
if (dist + w > ans) continue;
dfs(u, dst, K - 1, dist + w);
}
}
}
方法4:动态规划
//TODO
1334. 阈值距离内邻居最少的城市
方法1:Floyd
public int findTheCity(int N, int[][] edges, int distanceThreshold) {
int INF = Integer.MAX_VALUE;
int[][] graph = new int[N][N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
graph[i][j] = (i == j) ? 0 : INF;
}
}
for (int[] e : edges) {
int u = e[0], v = e[1], w = e[2];
graph[u][v] = w;
graph[v][u] = w;
}
for (int k = 0; k < N; k++) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (i == j || graph[i][k] == INF || graph[k][j] == INF) continue;
graph[i][j] = Math.min(graph[i][j], graph[i][k] + graph[k][j]);
}
}
}
PrintUtils.printMatrix(graph);
int res = -1, min = N + 1;
for (int i = 0; i < N; i++) {
int cnt = 0;
for (int j = 0; j < N; j++) {
if (i != j && graph[i][j] <= distanceThreshold) {
cnt++;
}
}
if (min >= cnt) {
min = cnt;
res = i;
}
}
return res;
}
814.无向图中的最短路径
方法1:BFS
class UndirectedGraphNode {
int label;
List<UndirectedGraphNode> neighbors;
UndirectedGraphNode(int x) {
label = x;
neighbors = new ArrayList<UndirectedGraphNode>();
}
}
public int shortestPath(List<UndirectedGraphNode> graph, UndirectedGraphNode A, UndirectedGraphNode B) {
Queue<UndirectedGraphNode> q = new LinkedList<>();
Set<UndirectedGraphNode> visited = new HashSet<>();
q.offer(A);
visited.add(A);
int res = 0;
while (!q.isEmpty()) {
int size = q.size();
res++;
for (int i = 0; i < size; i++) {
UndirectedGraphNode curr = q.poll();
for (UndirectedGraphNode next : curr.neighbors) {
System.out.printf("%d-->%d\n", curr.label, next.label);
if (visited.contains(next)) continue;
if (next.label == B.label) return res;
q.offer(next);
visited.add(next);
}
}
}
return -1;
}
1563.目的地的最短路径
方法1:BFS
int R, C;
int[][] dirs = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
public int shortestPath(int[][] A) {
// Write your code here
R = A.length;
C = A[0].length;
Queue<int[]> q = new LinkedList<>();
boolean[][] vis = new boolean[R][C];
q.offer(new int[]{0, 0});
vis[0][0] = true;
int steps = 0;
while (!q.isEmpty()) {
int size = q.size();
steps++;
for (int i = 0; i < size; i++) {
int[] c = q.poll();
int cr = c[0], cc = c[1];
for (int[] d : dirs) {
int nr = cr + d[0], nc = cc + d[1];
if (!inArea(nr, nc) || vis[nr][nc]) continue;
if (A[nr][nc] == 2) return steps;
if (A[nr][nc] == 1) continue;
q.offer(new int[]{nr, nc});
vis[nr][nc] = true;
}
}
}
return -1;
}
private boolean inArea(int r, int c) {
return r >= 0 && r < R && c >= 0 && c < C;
}
方法2:DFS
- 回溯标记状态,vis控制元素是否访问
int R, C;
int[][] dirs = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
boolean[][] vis;
int res;
public int shortestPath(int[][] A) {
// Write your code here
R = A.length;
C = A[0].length;
vis = new boolean[R][C];
res = R * C;
dfs(A, 0, 0, 0);
return res == R * C ? -1 : res;
}
private void dfs(int[][] A, int r, int c, int steps) {
for (int[] d : dirs) {
int nr = r + d[0], nc = c + d[1];
if (!inArea(nr, nc) || vis[nr][nc]) continue;
if (A[nr][nc] == 2) {
steps++;
res = Math.min(res, steps);
return;
} else if (A[nr][nc] == 1) {
continue;
} else if (A[nr][nc] == 0) {
steps++;
vis[nr][nc] = true;
dfs(A, nr, nc, steps);
vis[nr][nc] = false;
steps--;
}
}
}
private boolean inArea(int r, int c) {
return r >= 0 && r < R && c >= 0 && c < C;
}