一、Problem
小明目前在做一份毕业旅行的规划。打算从北京出发,分别去若干个城市,然后再回到北京,每个城市之间均乘坐高铁,且每个城市只去一次。由于经费有限,希望能够通过合理的路线安排尽可能的省一些路上的花销。给定一组城市和每对城市之间的火车票的价钱,找到每个城市只访问一次并返回起点的最小车费花销。
输入描述:
城市个数n(1<n≤20,包括北京)
城市间的车票价钱 n 行 n 列的矩阵 m[n][n]
输出描述:
最小车费花销 s
输入例子1:
4
0 2 6 5
2 0 4 4
6 4 0 2
5 4 2 0
输出例子1:
13
例子说明1:
共 4 个城市,城市 1 和城市 1 的车费为0,城市 1 和城市 2 之间的车费为 2,
城市 1 和城市 3 之间的车费为 6,城市 1 和城市 4 之间的车费为 5,依次类推。
假设任意两个城市之间均有单程票可购买,且票价在1000元以内,无需考虑极端情况。
二、Solution
方法一:dp
- 定义状态:
- 表示从城市 出发,经过城市集合 中各个顶点仅一次,并回到发点 的最短距离。
- 思考状态转移方程:
- 如果 是空集,
dp[i][j] = dp[i][0] = dist[i][0]
表示从 出发,经过 0 个城市,并回到出发点 s 的最短距离,也就是从城市 回到出发城市 的最短路距离了。 - 否则,
dp[i][k] = min(dp[i][j], dp[i][k] + dp[i][j ^ (1 <<(k-1))])
,j ^ (1 << (k - 1))
表示从 出发,经过城市集合 (不包含城市 ),并回到出发点 的最短距离。
- 如果 是空集,
- 思考初始化:
- 同上
- 思考输出:,
tot = 1 << (n-1) - 1
java 位运算优先级杀我:(1 << (n - 1)) - 1
这样写是对的,但 1 << (n - 1) - 1
这样写是错的,原因是左移运算符优先级比减法低。
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
static class Solution {
void init() {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
int n = sc.nextInt(), tot = (1 << (n - 1)) - 1, g[][] = new int[n][n], dp[][] = new int[n][1<<n];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) g[i][j] = sc.nextInt();
for (int i = 0; i < n; i++) dp[i][0] = g[i][0];
for (int j = 1; j <= tot; j++)
for (int i = 0; i < n; i++) {
dp[i][j] = Integer.MAX_VALUE;
if ((j & (1 << (i-1))) != 0)
continue;
for (int k = 1; k < n; k++) {
if ((j & (1 << (k-1))) > 0)
dp[i][j] = Math.min(dp[i][j], g[i][k] + dp[k][j ^ (1 << (k-1))]);
}
}
System.out.println(dp[0][tot]);
}
}
public static void main(String[] args) throws IOException {
Solution s = new Solution();
s.init();
}
}
复杂度分析
- 时间复杂度:,
- 空间复杂度:,