一、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();
}
}
複雜度分析
- 時間複雜度:,
- 空間複雜度:,