【Lintcode】1891. Travel Plan

記錄演算法發表於2020-11-27

題目地址:

https://www.lintcode.com/problem/travel-plan/description

給定一個二維矩陣 A A A A [ i ] [ j ] A[i][j] A[i][j]代表從城市 i i i到城市 j j j需要的花費( A A A對角線是 0 0 0,但不一定對稱)。一共 n n n個城市,編號為 0 ∼ n − 1 0\sim n-1 0n1。從城市 0 0 0出發,要求不重不漏走完其它城市再回到 0 0 0,問最少花費是多少。

思路是動態規劃。這裡的關鍵在於狀態壓縮。設 f [ s ] [ v ] f[s][v] f[s][v]表示已經訪問過的城市集合為 s s s s s s的二進位制位表示訪問過哪些城市, 1 1 1表示訪問過, 0 0 0表示沒訪問過),當前在 v v v,訪問所有剩下的城市回到城市 0 0 0的最少花費。那麼 f [ 2 n − 1 ] [ 0 ] = 0 f[2^n-1][0]=0 f[2n1][0]=0,表示所有城市都訪問過了,當前在城市 0 0 0,那不用走了,花費就是 0 0 0。另外,通過列舉從當前的城市 v v v出發,接下來訪問哪個城市,有: f [ s ] [ v ] = min ⁡ ( s > > u ) & 1 ≠ 0 f [ s ∣ ( 1 < < u ) ] + A [ v ] [ u ] f[s][v]=\min_{(s>> u)\&1\ne 0}f[s|(1<<u)]+A[v][u] f[s][v]=(s>>u)&1=0minf[s(1<<u)]+A[v][u]其中 u u u就是訪問的下一個城市,它之前應該沒訪問過。最後返回的就是 f [ 0 ] [ 0 ] f[0][0] f[0][0]。程式碼如下:

import java.util.Arrays;

public class Solution {
    /**
     * @param arr: the distance between any two cities
     * @return: the minimum distance Alice needs to walk to complete the travel plan
     */
    public int travelPlan(int[][] arr) {
        // Write your code here.
        if (arr == null || arr.length == 0) {
            return 0;
        }
        
        int n = arr.length;
        
        // dp[s][v]表示已經訪問過的城市集合是s,當前在v,並且從v出發訪問剩餘所有城市回到0的最少花費
        int[][] dp = new int[1 << n][n];
        for (int[] row : dp) {
            Arrays.fill(row, Integer.MAX_VALUE - 10000);
        }
        
        dp[(1 << n) - 1][0] = 0;
    
        for (int s = (1 << n) - 2; s >= 0; s--) {
        	// 列舉當前位置
            for (int v = 0; v < n; v++) {
            	// 列舉下一個要到達的位置
                for (int u = 0; u < n; u++) {
                	// 如果u之前沒訪問過,則列舉之
                    if (((s >> u) & 1) == 0) {
                        dp[s][v] = Math.min(dp[s][v], dp[s | (1 << u)][u] + arr[v][u]);
                    }
                }
            }
        }
    
        return dp[0][0];
    }
}

時間複雜度 O ( n 2 2 n ) O(n^22^n) O(n22n),空間 O ( n 2 n ) O(n2^n) O(n2n)

相關文章