leetcode
leetcode 3001 ~ 3050
志愿者调配

志愿者调配

难度:

标签:

题目描述

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个场馆的人数是为了在逆向操作过程中能够同时跟踪和计算每个场馆人数相对于第0个场馆的变化。虚数部分(1j表示)用来模拟第0个场馆的人数变化,而实数部分用来表示其他场馆的人数。这种方法的优势在于,它可以在不知道具体初始人数的情况下,通过算术运算维护场馆间人数的相对变化。这样,最终只需解一个方程就能找出第0个场馆的实际初始人数,从而计算出所有场馆的初始人数。
🦆
逆向操作过程中,对于第二种和第三种调配方案,为什么可以直接将对应场馆的人数加减到相邻场馆?这样的操作是否会改变最终的总人数?
逆向操作中,第二种和第三种调配方案涉及到将一个场馆的人数加到或者减去相邻场馆的人数。这种操作可以直接进行,因为它们是调配方案的逆操作,即如果原来是增加,则逆向操作时就减少;如果原来是减少,则逆向操作时就增加。这样的操作不会改变最终的总人数,因为只是在场馆之间重新分配人数,没有增加或减少总人数。
🦆
在倒推结束后,如何确保通过解方程得到的第0个场馆的初始人数是整数?
在倒推结束后,通过解方程来确定第0个场馆的初始人数,确保它是整数的关键在于方程设置的合理性和数学计算的准确性。方程是基于总人数和每个场馆人数变化的关系建立的。如果所有输入数据(如总人数和最终各场馆人数)都是整数,并且所有操作(如加倍或加减相邻场馆人数)都保持整数的性质,那么解出的第0个场馆的初始人数也应该是整数。这依赖于问题的设定和算法的正确实现。

相关问题