动态规划-状态压缩-707. 最优账户结余
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];
}

浙公网安备 33010602011771号