【Leetcode】847. Shortest Path Visiting All Nodes

Subject address:

https://leetcode.com/problems/shortest-path-visiting-all-nodes/

Given a nnn- order undirected connected graph, vertex number1 ∼ n − 1 1\sim n-11n1. Find the shortest Hamilton loop length.

For the BFS solution refer to https://blog.csdn.net/qq_46105170/article/details/109913464 . The following describes the dynamic programming method.

State compression can be used here to make a number xxThe binary bits of x respectively indicate whether a certain vertex has been visited, and then letf [i] [x] f[i][x]f [ i ] [ x ] means that it is currently at numberiithe vertex of i , and the situation facing isxxWhen x (meaning that the status of the visited and unvisited points isxxx ), the length of the shortest path of all points. Thenf [i] [2 n − 1] = 0 f[i][2^n-1]=0f[i][2n1]=0 , which means that all points have been completed. Obviously the shortest path length is0 00 . For other cases, there are: f [i] [s] = 1 + min ⁡ i → k {f [k] [s ∣ (1 <<k)]} f[i][s]=1+\min_ {i\to k}\{f[k][s|(1<<k)]\}f[i][s]=1+ikme{ f[k][s(1<<k ) ] } Last solutionmin ⁡ i = 0, 1, .. ., n − 1 f [i] [1 <<i] \ min_ {i = 0,1, ..., n-1} f [i] [1 << i]mini=0,1,...,n1f[i][1<<i ] . Obviously when looping,sss Required2 n − 2 → 0 2 ^ {n} -2 \ to 02n20 to loop in this order, but there is a problem here, if you are looking forf [i] [s] f[i][s]When f [ i ] [ s ] , it happens to use a certainf [j] [s] f[j][s]f [ j ] [ s ] (The key here is thats ∣ (1 <<k) = ss|(1<<k)=ss(1<<k)=s ), but at this timef [j] [s] f[j][s]f [ j ] [ s ] may not be calculated yet, which will lead to wrong answers. The solution is to find a certainf [i] [s] f[i][s]When f [ i ] [ s ] is updated to a smaller value, the loop will be repeated again until the loop cannot get a better solution. Here is why there is no infinite loop. If there is an infinite loop, you will get the situation of "update yourself", but the edge weights of this graph are all1 11. There is no negative loop, so there is no endless loop. code show as below:

import java.util.Arrays;

public class Solution {
    
    
    public int shortestPathLength(int[][] graph) {
    
    
        int n = graph.length;
        int[][] dp = new int[n][1 << n];
        for (int[] row : dp) {
    
    
            Arrays.fill(row, n * n);
            row[(1 << n) - 1] = 0;
        }
        
        for (int s = (1 << n) - 2; s > 0; s--) {
    
    
            for (boolean repeat = true; repeat; ) {
    
    
                repeat = false;
                for (int cur = 0; cur < n; cur++) {
    
    
                    if ((s >> cur & 1) == 1) {
    
    
                        for (int next : graph[cur]) {
    
    
                            int ne = s | (1 << next);
                            if (1 + dp[next][ne] < dp[cur][s]) {
    
    
                                dp[cur][s] = 1 + dp[next][ne];
                                // 一旦发现被更新为更优解了,则追加一次循环
                                repeat = true;
                            }
                        }
                    }
                }
            }
        }
        
        int res = n * n;
        for (int i = 0; i < n; i++) {
    
    
            res = Math.min(res, dp[i][1 << i]);
        }
        
        return res;
    }
}

Time complexity O (V 2 2 V) O(V^22^V)O ( V22V ), spaceO (V 2 V) O(V2^V)O ( V 2V )

The status setting is not unique. We can also set f [i] [s] f[i][s]F [ I ] [ S ]为从iii start and form statesss shortest length. The initial condition at this time isf [i] [1 <<i] = 0 f[i][1<<i]=0f[i][1<<i]=0 , the answer to be returned ismin ⁡ i = 0, 1,.... N − 1 f [i] [2 n − 1] \min_{i=0,1,....n-1} f[i][2^n-1]mini=0,1,....n1f[i][2n1],转移方程为: f [ k ] [ s ∣ ( 1 < < k ) ] = 1 + min ⁡ i → k { f [ i ] [ s ] } f[k][s|(1<<k)]=1+\min_{i\to k}\{f[i][s]\} f[k][s(1<<k)]=1+ikme{ f [ i ] [ s ] } The code is as follows:

import java.util.Arrays;

public class Solution {
    
    
    public int shortestPathLength(int[][] graph) {
    
    
        int n = graph.length;
        int[][] dp = new int[n][1 << n];
        for (int i = 0; i < n; i++) {
    
    
            Arrays.fill(dp[i], n * n);
            dp[i][1 << i] = dp[i][0] = 0;
        }
        
        for (int s = 1; s < 1 << n; s++) {
    
    
            for (boolean repeat = true; repeat; ) {
    
    
                repeat = false;
                for (int cur = 0; cur < n; cur++) {
    
    
                    if ((s >> cur & 1) == 1) {
    
    
                        for (int next : graph[cur]) {
    
    
                            if (1 + dp[cur][s] < dp[next][s | (1 << next)]) {
    
    
                                dp[next][s | (1 << next)] = 1 + dp[cur][s];
                                repeat = true;
                            }
                        }
                    }
                }
            }
        }
        
        int res = n * n;
        for (int i = 0; i < n; i++) {
    
    
            res = Math.min(res, dp[i][(1 << n) - 1]);
        }
        
        return res;
    }
}

The time and space complexity is the same.

Guess you like

Origin blog.csdn.net/qq_46105170/article/details/112761116