连通两组点的最小成本
难度:
标签:
题目描述
给你两组点,其中第一组中有 size1
个点,第二组中有 size2
个点,且 size1 >= size2
。
任意两点间的连接成本 cost
由大小为 size1 x size2
矩阵给出,其中 cost[i][j]
是第一组中的点 i
和第二组中的点 j
的连接成本。如果两个组中的每个点都与另一组中的一个或多个点连接,则称这两组点是连通的。换言之,第一组中的每个点必须至少与第二组中的一个点连接,且第二组中的每个点必须至少与第一组中的一个点连接。
返回连通两组点所需的最小成本。
示例 1:
输入:cost = [[15, 96], [36, 2]] 输出:17 解释:连通两组点的最佳方法是: 1--A 2--B 总成本为 17 。
示例 2:
输入:cost = [[1, 3, 5], [4, 1, 1], [1, 5, 3]] 输出:4 解释:连通两组点的最佳方法是: 1--A 2--B 2--C 3--A 最小成本为 4 。 请注意,虽然有多个点连接到第一组中的点 2 和第二组中的点 A ,但由于题目并不限制连接点的数目,所以只需要关心最低总成本。
示例 3:
输入:cost = [[2, 5, 1], [3, 4, 7], [8, 1, 2], [6, 2, 4], [3, 8, 8]] 输出:10
提示:
size1 == cost.length
size2 == cost[i].length
1 <= size1, size2 <= 12
size1 >= size2
0 <= cost[i][j] <= 100
代码结果
运行时间: 371 ms, 内存: 16.0 MB
/*
* Solution Overview:
* Similar to the Java solution, but utilizing Java Streams for concise and readable code. We will still use dynamic programming to keep track of the minimum costs for each combination of connected points.
*/
import java.util.List;
import java.util.stream.IntStream;
import java.util.Arrays;
public class SolutionStream {
public int connectTwoGroups(List<List<Integer>> cost) {
int size1 = cost.size();
int size2 = cost.get(0).size();
int maxMask = 1 << size1;
int[] dp = new int[maxMask];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
// Using Java Streams to calculate minimum costs
IntStream.range(0, maxMask).forEach(mask ->
IntStream.range(0, size2).forEach(j -> {
int currentCost = IntStream.range(0, size1)
.filter(i -> (mask & (1 << i)) != 0)
.map(i -> cost.get(i).get(j))
.sum();
IntStream.iterate(mask, subMask -> (subMask - 1) & mask)
.limit(1 << size1)
.forEach(subMask -> dp[mask] = Math.min(dp[mask], dp[subMask] + currentCost));
})
);
return Arrays.stream(dp).min().orElse(Integer.MAX_VALUE);
}
}
解释
方法:
这道题本质上是一个最小成本完全匹配问题,可以通过动态规划的方式解决。动态规划数组 `f` 的大小为 `1 << size2`,代表第二组中的点的所有可能的连接状态。每个位对应一个点,若该位为1,则表示对应的点已被连接。\n\n1. 初始化 `f` 数组,其中 `f[0]` 为0,表示没有点被连接的状态。对于每个点j,计算如果仅连接该点的最小成本,更新 `f` 数组中对应状态的值。\n2. 针对第一组中的每个点,更新 `f` 数组。对于每一个已有的状态 `j`,遍历第二组中的所有点,并尝试将当前的点与第二组中的每个点相连接,更新状态。\n3. 最终,`f[-1]` 即包含所有第二组点都被连接的状态,其值为所需的最小成本。
时间复杂度:
O(size1 * size2 * 2^size2)
空间复杂度:
O(2^size2)
代码细节讲解
🦆
在动态规划解法中,数组`f`的索引表示什么含义?每个位的0和1分别代表什么状态?
▷🦆
为什么初始化动态规划数组`f`时,除了`f[0]`设置为0,其他都设置为无穷大`float('inf')`?
▷🦆
解法中提到的`尝试将当前行的点与第二组中的每个点连接`具体是如何实现的?请详细解释更新`f`数组的过程。
▷🦆
在动态规划中,为什么需要单独处理只连接一个点的情况?这一步是如何优化整体解决方案的?
▷