志愿者调配
难度:
标签:
题目描述
English description is not available for the problem. Please switch to Chinese.
代码结果
运行时间: 286 ms, 内存: 38.2 MB
/*
* 思路:
* 1. 逆向操作所有的调配方案,恢复初始状态。
* 2. 建立场馆和其相邻场馆的图。
* 3. 根据最终状态和总人数计算初始状态。
*/
import java.util.*;
import java.util.stream.*;
public class VolunteerAllocationStream {
public int[] findInitialVolunteers(int[] finalCnt, int totalNum, int[][] edges, int[][] plans) {
int n = finalCnt.length + 1;
int[] initialCnt = new int[n];
initialCnt[0] = totalNum - Arrays.stream(finalCnt).sum();
System.arraycopy(finalCnt, 0, initialCnt, 1, finalCnt.length);
Map<Integer, List<Integer>> graph = Arrays.stream(edges).collect(Collectors.groupingBy(edge -> edge[0], Collectors.mapping(edge -> edge[1], Collectors.toList())));
Arrays.stream(edges).forEach(edge -> graph.computeIfAbsent(edge[1], k -> new ArrayList<>()).add(edge[0]));
List<int[]> reversedPlans = Arrays.stream(plans).collect(Collectors.toList());
Collections.reverse(reversedPlans);
reversedPlans.forEach(plan -> {
int type = plan[0];
int idx = plan[1];
if (type == 1) {
initialCnt[idx] *= 2;
} else if (type == 2) {
graph.getOrDefault(idx, new ArrayList<>()).forEach(neighbor -> initialCnt[neighbor] -= initialCnt[idx]);
} else if (type == 3) {
graph.getOrDefault(idx, new ArrayList<>()).forEach(neighbor -> initialCnt[neighbor] += initialCnt[idx]);
}
});
return initialCnt;
}
}
解释
方法:
这个题解采用的是数学倒推的方法。首先,我们知道最终各个场馆的志愿者人数,但是需要求出初始时各个场馆的志愿者人数。为了实现这一点,我们可以从最后一天的调配方案开始,逆向操作,直到回到第一天。在这个过程中,我们使用虚数1j来表示第0个场馆的人数,这样可以将所有场馆的人数表示为实数和虚数的组合,其中实数部分表示最终人数,虚数部分表示相对于第0个场馆的人数变化。最后,通过总人数和各场馆人数之间的关系,可以解出第0个场馆的初始人数,进而得到所有场馆的初始人数。
时间复杂度:
O(E + PN)
空间复杂度:
O(N + E)
代码细节讲解
🦆
为什么在解决方案中使用虚数来表示第0个场馆的人数?这种方法有什么特别的优势吗?
▷🦆
逆向操作过程中,对于第二种和第三种调配方案,为什么可以直接将对应场馆的人数加减到相邻场馆?这样的操作是否会改变最终的总人数?
▷🦆
在倒推结束后,如何确保通过解方程得到的第0个场馆的初始人数是整数?
▷