跳转至

2247. K 条高速公路的最大旅行费用 🔒

题目描述

一系列高速公路连接从 0n - 1n 个城市。给定一个二维整数数组 highways,其中 highways[i] = [city1i, city2i, tolli] 表示有一条高速公路连接 city1icity2i,允许一辆汽车从 city1i 前往 city2i反之亦然,费用为 tolli

给你一个整数 k,你要正好经过 k 条公路。你可以从任何一个城市出发,但在旅途中每个城市最多只能访问一次。

返回您旅行的最大费用。如果没有符合要求的行程,则返回 -1

示例 1:

输入: n = 5, highways = [[0,1,4],[2,1,3],[1,4,11],[3,2,3],[3,4,2]], k = 3
输出: 17
解释:
一个可能的路径是从 0 -> 1 -> 4 -> 3。这次旅行的费用是 4 + 11 + 2 = 17。
另一种可能的路径是从 4 -> 1 -> 2 -> 3。这次旅行的费用是 11 + 3 + 3 = 17。
可以证明,17 是任何有效行程的最大可能费用。
注意,旅行 4 -> 1 -> 0 -> 1 是不允许的,因为你访问了城市 1 两次。

 

示例 2:

输入: n = 4, highways = [[0,1,3],[2,3,2]], k = 2
输出: -1
解释: 没有长度为 2 的有效行程,因此返回-1。

 

提示:

  • 2 <= n <= 15
  • 1 <= highways.length <= 50
  • highways[i].length == 3
  • 0 <= city1i, city2i <= n - 1
  • city1i != city2i
  • 0 <= tolli <= 100
  • 1 <= k <= 50
  • 没有重复的高速公路。

解法

方法一:状态压缩动态规划

我们注意到,题目要求正好经过 $k$ 条公路,而每个城市最多只能访问一次,城市的数量为 $n$,因此,我们最多只能经过 $n - 1$ 条公路。所以,如果 $k \ge n$,那么我们无法满足题目要求,直接返回 $-1$ 即可。

另外,我们也可以发现,城市数量 $n$ 不超过 $15$,这提示我们可以考虑使用状态压缩动态规划的方法求解本题。我们用一个长度为 $n$ 的二进制数表示当前已经经过的城市,其中第 $i$ 位为 $1$ 表示已经经过了第 $i$ 个城市,为 $0$ 表示还没有经过第 $i$ 个城市。

我们用 $f[i][j]$ 表示当前已经经过的城市为 $i$,最后一个经过的城市为 $j$ 的情况下,最大的旅行费用。初始时 $f[2^i][i]=0$,其余 $f[i][j]=-\infty$。

考虑 $f[i][j]$ 如何进行状态转移。对于 $f[i]$,我们枚举所有城市 $j$,如果 $i$ 的第 $j$ 位为 $1$,那么我们就可以从其它城市 $h$ 经过公路到达城市 $j$,此时 $f[i][j]$ 的值为 $f[i][h]+cost(h, j)$ 的最大值,其中 $cost(h, j)$ 表示从城市 $h$ 到城市 $j$ 的旅行费用。因此,我们可以得到状态转移方程:

$$ f[i][j]=\max_{h \in \textit{city}}{f[i \backslash j][h]+cost(h, j)} $$

其中 $i \backslash j$ 表示将 $i$ 的第 $j$ 位变为 $0$。

求出 $f[i][j]$ 后,我们判断经过的城市数量是否为 $k+1$,即 $i$ 的二进制表示中 $1$ 的个数是否为 $k+1$,如果是,那么我们就更新答案为 $ans = \max(ans, f[i][j])$。

时间复杂度 $O(2^n \times n^2)$,空间复杂度 $O(2^n \times n)$。其中 $n$ 表示城市数量。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution:
    def maximumCost(self, n: int, highways: List[List[int]], k: int) -> int:
        if k >= n:
            return -1
        g = defaultdict(list)
        for a, b, cost in highways:
            g[a].append((b, cost))
            g[b].append((a, cost))
        f = [[-inf] * n for _ in range(1 << n)]
        for i in range(n):
            f[1 << i][i] = 0
        ans = -1
        for i in range(1 << n):
            for j in range(n):
                if i >> j & 1:
                    for h, cost in g[j]:
                        if i >> h & 1:
                            f[i][j] = max(f[i][j], f[i ^ (1 << j)][h] + cost)
                if i.bit_count() == k + 1:
                    ans = max(ans, f[i][j])
        return ans
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Solution {
    public int maximumCost(int n, int[][] highways, int k) {
        if (k >= n) {
            return -1;
        }
        List<int[]>[] g = new List[n];
        Arrays.setAll(g, h -> new ArrayList<>());
        for (int[] h : highways) {
            int a = h[0], b = h[1], cost = h[2];
            g[a].add(new int[] {b, cost});
            g[b].add(new int[] {a, cost});
        }
        int[][] f = new int[1 << n][n];
        for (int[] e : f) {
            Arrays.fill(e, -(1 << 30));
        }
        for (int i = 0; i < n; ++i) {
            f[1 << i][i] = 0;
        }
        int ans = -1;
        for (int i = 0; i < 1 << n; ++i) {
            for (int j = 0; j < n; ++j) {
                if ((i >> j & 1) == 1) {
                    for (var e : g[j]) {
                        int h = e[0], cost = e[1];
                        if ((i >> h & 1) == 1) {
                            f[i][j] = Math.max(f[i][j], f[i ^ (1 << j)][h] + cost);
                        }
                    }
                }
                if (Integer.bitCount(i) == k + 1) {
                    ans = Math.max(ans, f[i][j]);
                }
            }
        }
        return ans;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Solution {
public:
    int maximumCost(int n, vector<vector<int>>& highways, int k) {
        if (k >= n) {
            return -1;
        }
        vector<pair<int, int>> g[n];
        for (auto& h : highways) {
            int a = h[0], b = h[1], cost = h[2];
            g[a].emplace_back(b, cost);
            g[b].emplace_back(a, cost);
        }
        int f[1 << n][n];
        memset(f, -0x3f, sizeof(f));
        for (int i = 0; i < n; ++i) {
            f[1 << i][i] = 0;
        }
        int ans = -1;
        for (int i = 0; i < 1 << n; ++i) {
            for (int j = 0; j < n; ++j) {
                if (i >> j & 1) {
                    for (auto& [h, cost] : g[j]) {
                        if (i >> h & 1) {
                            f[i][j] = max(f[i][j], f[i ^ (1 << j)][h] + cost);
                        }
                    }
                }
                if (__builtin_popcount(i) == k + 1) {
                    ans = max(ans, f[i][j]);
                }
            }
        }
        return ans;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
func maximumCost(n int, highways [][]int, k int) int {
    if k >= n {
        return -1
    }
    g := make([][][2]int, n)
    for _, h := range highways {
        a, b, cost := h[0], h[1], h[2]
        g[a] = append(g[a], [2]int{b, cost})
        g[b] = append(g[b], [2]int{a, cost})
    }
    f := make([][]int, 1<<n)
    for i := range f {
        f[i] = make([]int, n)
        for j := range f[i] {
            f[i][j] = -(1 << 30)
        }
    }
    for i := 0; i < n; i++ {
        f[1<<i][i] = 0
    }
    ans := -1
    for i := 0; i < 1<<n; i++ {
        for j := 0; j < n; j++ {
            if i>>j&1 == 1 {
                for _, e := range g[j] {
                    h, cost := e[0], e[1]
                    if i>>h&1 == 1 {
                        f[i][j] = max(f[i][j], f[i^(1<<j)][h]+cost)
                    }
                }
            }
            if bits.OnesCount(uint(i)) == k+1 {
                ans = max(ans, f[i][j])
            }
        }
    }
    return ans
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
function maximumCost(n: number, highways: number[][], k: number): number {
    if (k >= n) {
        return -1;
    }
    const g: [number, number][][] = Array.from({ length: n }, () => []);
    for (const [a, b, cost] of highways) {
        g[a].push([b, cost]);
        g[b].push([a, cost]);
    }
    const f: number[][] = Array(1 << n)
        .fill(0)
        .map(() => Array(n).fill(-(1 << 30)));
    for (let i = 0; i < n; ++i) {
        f[1 << i][i] = 0;
    }
    let ans = -1;
    for (let i = 0; i < 1 << n; ++i) {
        for (let j = 0; j < n; ++j) {
            if ((i >> j) & 1) {
                for (const [h, cost] of g[j]) {
                    if ((i >> h) & 1) {
                        f[i][j] = Math.max(f[i][j], f[i ^ (1 << j)][h] + cost);
                    }
                }
            }
            if (bitCount(i) === k + 1) {
                ans = Math.max(ans, f[i][j]);
            }
        }
    }
    return ans;
}

function bitCount(i: number): number {
    i = i - ((i >>> 1) & 0x55555555);
    i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
    i = (i + (i >>> 4)) & 0x0f0f0f0f;
    i = i + (i >>> 8);
    i = i + (i >>> 16);
    return i & 0x3f;
}

评论