难度: Medium
Submission
运行时间: 286 ms
内存: 38.2 MB
class Solution: def volunteerDeployment(self, finalCnt: List[int], totalNum: int, edges: List[List[int]], plans: List[List[int]]) -> List[int]: # 用虚数1j 表示场馆0在最后一天的人数 # 倒推,然后解方程 n = len(finalCnt) + 1 g = [[] for _ in range(n)] for a, b in edges: g[a].append(b) g[b].append(a) v = [1j] + finalCnt for scheme, venue in reversed(plans): if scheme == 1: v[venue] *= 2 elif scheme == 2: for nxt in g[venue]: v[nxt] -= v[venue] else: for nxt in g[venue]: v[nxt] += v[venue] t = sum(v) zero = (totalNum - t.real) // t.imag return [floor(x.real + x.imag * zero) for x in v]
Explain
这个题解采用的是数学倒推的方法。首先,我们知道最终各个场馆的志愿者人数,但是需要求出初始时各个场馆的志愿者人数。为了实现这一点,我们可以从最后一天的调配方案开始,逆向操作,直到回到第一天。在这个过程中,我们使用虚数1j来表示第0个场馆的人数,这样可以将所有场馆的人数表示为实数和虚数的组合,其中实数部分表示最终人数,虚数部分表示相对于第0个场馆的人数变化。最后,通过总人数和各场馆人数之间的关系,可以解出第0个场馆的初始人数,进而得到所有场馆的初始人数。
时间复杂度: O(E + PN)
空间复杂度: O(N + E)
class Solution: def volunteerDeployment(self, finalCnt: List[int], totalNum: int, edges: List[List[int]], plans: List[List[int]]) -> List[int]: # 用虚数1j 表示场馆0在最后一天的人数 # 倒推,然后解方程 n = len(finalCnt) + 1 g = [[] for _ in range(n)] for a, b in edges: g[a].append(b) g[b].append(a) v = [1j] + finalCnt for scheme, venue in reversed(plans): if scheme == 1: v[venue] *= 2 elif scheme == 2: for nxt in g[venue]: v[nxt] -= v[venue] else: for nxt in g[venue]: v[nxt] += v[venue] t = sum(v) zero = (totalNum - t.real) // t.imag return [floor(x.real + x.imag * zero) for x in v]
Explore
在这个解决方案中,使用虚数来表示第0个场馆的人数是为了在逆向操作过程中能够同时跟踪和计算每个场馆人数相对于第0个场馆的变化。虚数部分(1j表示)用来模拟第0个场馆的人数变化,而实数部分用来表示其他场馆的人数。这种方法的优势在于,它可以在不知道具体初始人数的情况下,通过算术运算维护场馆间人数的相对变化。这样,最终只需解一个方程就能找出第0个场馆的实际初始人数,从而计算出所有场馆的初始人数。
逆向操作中,第二种和第三种调配方案涉及到将一个场馆的人数加到或者减去相邻场馆的人数。这种操作可以直接进行,因为它们是调配方案的逆操作,即如果原来是增加,则逆向操作时就减少;如果原来是减少,则逆向操作时就增加。这样的操作不会改变最终的总人数,因为只是在场馆之间重新分配人数,没有增加或减少总人数。
在倒推结束后,通过解方程来确定第0个场馆的初始人数,确保它是整数的关键在于方程设置的合理性和数学计算的准确性。方程是基于总人数和每个场馆人数变化的关系建立的。如果所有输入数据(如总人数和最终各场馆人数)都是整数,并且所有操作(如加倍或加减相邻场馆人数)都保持整数的性质,那么解出的第0个场馆的初始人数也应该是整数。这依赖于问题的设定和算法的正确实现。