2020-04-07 16:52:12
问题描述:
给一有向图,每一条边用一个 三元组
表示, 比如 [u, v, w]
代表权值为 w
的从 u
到 v
的一条边. 计算出保证每个点的权重相等需要添加的最少的边数. 也就是说, 指向这一点的边权重总和等于这个点指向其他点的边权重之和.
样例
样例1
输入: [[0,1,10],[2,0,5]] 输出: 2 说明: 需要添加两条边 它们是 [1,0,5] 以及 [1,2,5]
样例2
输入: [[0,1,10],[1,0,1],[1,2,5],[2,0,5]] 输出: 1 说明: 只需要添加一条边 [1,0,4]
注意事项
- 注意 u ≠ v 且 w > 0
- 下标不一定是线性的, 比如 顶点下标可以为 0,1,2, 也可以为 0,2,6.
问题求解:
本题可以使用动态规划来进行求解,对于一个集合,如何其和为0,那么就是一个合法的子集,我们只需要去遍历其合法的子集组成就可以得到最终的结果。
时间复杂度:O(2 ^ n)
public int balanceGraph(int[][] edges) { Map<Integer, Integer> map = new HashMap<>(); for (int[] e : edges) { int from = e[0]; int to = e[1]; int w = e[2]; map.put(from, map.getOrDefault(from, 0) - w); map.put(to, map.getOrDefault(to, 0) + w); } int[] nums = new int[map.size()]; int len = 0; for (int v : map.values()) { if (v != 0) { nums[len++] = v; } } if (len == 0) return 0; int[] dp = new int[1 << len]; Arrays.fill(dp, Integer.MAX_VALUE / 2); for (int i = 1; i < dp.length; i++) { int sum = 0; int cnt = 0; for (int j = 0; j < len; j++) { if ((1 << j & i) != 0) { sum += nums[j]; cnt += 1; } } if (sum == 0) { dp[i] = cnt - 1; for (int j = 1; j < dp.length; j++) { if ((j & i) == j) { dp[i] = Math.min(dp[i], dp[j] + dp[i - j]); } } } } return dp[dp.length - 1]; }