https://www.nowcoder.com/questionTerminal/3d1adf0f16474c90b27a9954b71d125d

public static void main(String[] args) {
    int n = reader.nextInt();// 城市数目
    int[][] dist = new int[n][n]; // 距离矩阵,距离为欧式空间距离
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            dist[i][j] = reader.nextInt();

    int V = (1 << (n - 1)) - 1;// 对1进行左移n-1位,值刚好等于2^(n-1)
    // dp表,n行,2^(n-1)列
    int[][] dp = new int[n][V + 1];
    // 初始化dp表第一列
    for (int i = 0; i < n; i++) dp[i][0] = dist[i][0];

    //设想一个数组城市子集V[j],长度为V,且V[j] = j,对于V[j]即为压缩状态的城市集合
    //从1到V-1  用二进制表示的话,刚好可以映射成除了0号城市外的剩余n-1个城市在不在子集V[j],1代表在,0代表不在
    //若有总共有4个城市的话,除了第0号城市,对于1-3号城市
    //111 = V-1 = 2^3 - 1  = 7 ,从高位到低位表示3到1号城市都在子集中
    //而101 = 5 ,表示3,1号城市在子集中
    for (int j = 1; j <= V; j++) //这里j不仅是dp表的列坐标值,如上描述,j的二进制表示城市相应城市是否在子集中
        for (int i = 0; i < n; i++) { //这个i不仅代表城市号,还代表第i次迭代
            dp[i][j] = Integer.MAX_VALUE; //为了方便求最小值,先将其设为最大值
            if (((j >> (i - 1)) & 1) == 0) { //表示路径中不能有i号
                for (int k = 1; k < n; k++) { 
                    if (((j >> (k - 1)) & 1) == 1) { //遍历城市子集 路径j
                        //状态转移方程,例,dp[0][3] = dp[0][101] = 
                        // max(dp[0][3], dis[0][1]+dp[1][100], dis[0][3]+dp[3][001])
                        dp[i][j] = Math.min(dp[i][j], dist[i][k] + dp[k][j ^ (1 << (k - 1))]); //^异或
                    }
                }
            }
        }
    System.out.println(dp[0][V]);
}


hhhhh