解法一:动态规划——状态压缩dp
状态定义:f[i][j]
,这里i
的前n
个二进制位表示每个点是否被访问过(若被访问过则相应二进制位是1),也就是当前路径经过了哪些点;j
表示当前路径的终点是哪个点,也就表明i
中的第j
个二进制位必须为1
;
状态转移方程:对于f[i][j]
,当前路径的终点是j
,现在枚举终点的前一个点是哪个,找出其中的最小值。需注意,对终点的前一个点进行枚举时,需保证i
所表示路径包含这个点,也就表明i
中相应二进制位必须为1
;
import java.util.*;
public class Main{
static int N = 22;
static int[][] dist = new int[N][N];
static int[][] f = new int[1 << N][N];
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
for(int i = 0; i < n; i ++)
for(int j = 0; j < n; j ++)
dist[i][j] = sc.nextInt();
// 初始化
for(int i = 0; i < f.length; i ++)
for(int j = 0; j < f[0].length; j ++)
f[i][j] = (int)1e9;
f[1][0] = 0;
// dp
for(int i = 0; i < 1 << n; i ++)
for(int j = 1; j < n; j ++)
if(((i >> j) & 1) == 1) // i中的第j个二进制位必须为1
for(int k = 0; k < n; k ++){
if(((i >> k) & 1) == 1 && k != j) // 需保证i所表示路径包含这个点,也就表明i中相应二进制位必须为1
f[i][j] = Math.min(f[i][j], f[i - (1 << j)][k] + dist[k][j]);
}
System.out.println(f[(1 << n) - 1][n - 1]);
}
}