LCP 46. 志愿者调配
「力扣挑战赛」有 n
个比赛场馆(场馆编号从 0
开始),场馆之间的通道分布情况记录于二维数组 edges
中,edges[i]= [x, y]
表示第 i
条通道连接场馆 x
和场馆 y
(即两个场馆相邻)。初始每个场馆中都有一定人数的志愿者(不同场馆人数可能不同),后续 m
天每天均会根据赛事热度进行志愿者人数调配。调配方案分为如下三种:
idx
的场馆内的志愿者人数减半;idx
的场馆相邻的场馆的志愿者人数都加上编号为 idx
的场馆的志愿者人数;idx
的场馆相邻的场馆的志愿者人数都减去编号为 idx
的场馆的志愿者人数。所有的调配信息记录于数组 plans
中,plans[i] = [num,idx]
表示第 i
天对编号 idx
的场馆执行了第 num
种调配方案。
在比赛结束后对调配方案进行复盘时,不慎将第 0
个场馆的最终志愿者人数丢失,只保留了初始所有场馆的志愿者总人数 totalNum
,以及记录了第 1 ~ n-1
个场馆的最终志愿者人数的一维数组 finalCnt
。请你根据现有的信息求出初始每个场馆的志愿者人数,并按场馆编号顺序返回志愿者人数列表。
注意:
10^9
;示例 1:
输入:
finalCnt = [1,16], totalNum = 21, edges = [[0,1],[1,2]], plans = [[2,1],[1,0],[3,0]]
输出:
[5,7,9]
解释: {:height=200}
示例 2 :
输入:
finalCnt = [4,13,4,3,8], totalNum = 54, edges = [[0,3],[1,3],[4,3],[2,3],[2,5]], plans = [[1,1],[3,3],[2,5],[1,0]]
输出:
[10,16,9,4,7,8]
提示:
2 <= n <= 5*10^4
1 <= edges.length <= min((n * (n - 1)) / 2, 5*10^4)
0 <= edges[i][0], edges[i][1] < n
1 <= plans.length <= 10
1 <= plans[i][0] <=3
0 <= plans[i][1] < n
finalCnt.length = n-1
0 <= finalCnt[i] < 10^9
0 <= totalNum < 5*10^13
原站题解
java 解法, 执行用时: 98 ms, 内存消耗: 70.7 MB, 提交时间: 2023-09-14 00:47:02
class Solution { public int[] volunteerDeployment(int[] finalCnt, long totalNum, int[][] edges, int[][] plans) { int n = finalCnt.length + 1, m = plans.length; int[] oriParam = new int[n]; int[] oriCnt = new int[n]; oriParam[0] = 1; for (int i = 0; i < n - 1; i++) { oriCnt[i + 1] = finalCnt[i]; } HashMap<Integer, List<Integer>> related = new HashMap<>(); for (int[] e : edges) { //保存相邻场馆 addRelations(e[0], e[1], related); addRelations(e[1], e[0], related); } for (int i = m - 1; i >= 0; i--) { int idx = plans[i][1]; int num = plans[i][0]; //模拟 plans 的操作 operate(num, idx, oriParam, related); operate(num, idx, oriCnt, related); } //汇总k0,k1,k2...及 y - b0 - b1 - ... int param = 0; for (int i = 0; i < n; i++) { totalNum -= oriCnt[i]; param += oriParam[i]; } //求解x int x = (int) (totalNum / param); //将常数数组加上 k * x 即为初始值 for (int i = 0; i < n ; i++) { oriCnt[i] += oriParam[i] * x; } return oriCnt; } private void operate(int num, int idx, int[] array, HashMap<Integer, List<Integer>> related) { if (num == 1) array[idx] *= 2; else { for (int r : related.getOrDefault(idx, new ArrayList<>())) { if (num == 2) array[r] -= array[idx]; else array[r] += array[idx]; } } } private void addRelations(int x, int y, HashMap<Integer, List<Integer>> related) { List<Integer> relations = related.getOrDefault(x, new ArrayList<>()); relations.add(y); related.put(x, relations); } }
rust 解法, 执行用时: 276 ms, 内存消耗: 8.9 MB, 提交时间: 2023-09-14 00:45:58
impl Solution { pub fn volunteer_deployment(final_cnt: Vec<i32>, total_num: i64, mut edges: Vec<Vec<i32>>, mut plans: Vec<Vec<i32>>) -> Vec<i32> { use std::collections::BTreeMap; //需要解决的未知数 let mut to_solve: Vec<[i64;2]> = vec![]; to_solve.push([0, 1]); for i in 0..final_cnt.len() { to_solve.push([final_cnt[i] as i64, 0]); } //记录每个点与哪些点相连 let mut edges_map: BTreeMap<usize, Vec<usize>> = BTreeMap::new(); for edge in edges { let this = edge[0] as usize; let other = edge[1] as usize; if let Some(e) = edges_map.get_mut(&this) { e.push(other); } else { edges_map.insert(this, vec![other]); } if let Some(e) = edges_map.get_mut(&other) { e.push(this); } else { edges_map.insert(other, vec![this]); } } // println!("BTreeMap: {:?}", edges_map); //逆向推导 for plan in plans.into_iter().rev() { let num = plan[0] as u32; let idx = plan[1] as usize; if num == 1 { to_solve[idx][0] *= 2; to_solve[idx][1] *= 2; } else { let add_or_sub = (-1i64).pow(num+1); let known = to_solve[idx][0]; let unknown = to_solve[idx][1]; if let Some(others) = edges_map.get(&idx) { for other in others { to_solve[*other][0] += add_or_sub * known; to_solve[*other][1] += add_or_sub * unknown; } } } // println!("{:?}", plan); // println!("{:?}\n", to_solve); } //求值 let mut left = 0; let mut coefficient = 0; for [l, c] in to_solve.iter() { left += l; coefficient += c; } let x: i32 = ((total_num - left) / coefficient) as i32; to_solve.into_iter().map(|[a, b]| a as i32 + (b as i32)*x).collect::<Vec<i32>>() } }
golang 解法, 执行用时: 536 ms, 内存消耗: 21 MB, 提交时间: 2023-09-14 00:45:30
func volunteerDeployment(finalCnt []int, totalNum int64, edges [][]int, plans [][]int) []int { n := len(finalCnt) + 1 g := make([][]int, n) for _, e := range edges { u := e[0] v := e[1] g[u] = append(g[u], v) g[v] = append(g[v], u) } m := len(plans) tmp := make([][2]int, n) tmp[0] = [2]int{1, 0} for i, f := range finalCnt { tmp[i+1][1] = f } for i := m - 1; i >= 0; i-- { num := plans[i][0] idx := plans[i][1] if num == 1 { tmp[idx][0] *= 2 tmp[idx][1] *= 2 } else if num == 2 { for _, v := range g[idx] { tmp[v][0] -= tmp[idx][0] tmp[v][1] -= tmp[idx][1] } } else { for _, v := range g[idx] { tmp[v][0] += tmp[idx][0] tmp[v][1] += tmp[idx][1] } } } var sum0, sum1 int for _, t := range tmp { sum0 += t[0] sum1 += t[1] } res := make([]int, n) x := int((totalNum - int64(sum1)) / int64(sum0)) var sum int for i := 1; i < n; i++ { res[i] = tmp[i][0]*x + tmp[i][1] sum += res[i] } res[0] = int(totalNum - int64(sum)) return res }
python3 解法, 执行用时: 420 ms, 内存消耗: 38.1 MB, 提交时间: 2023-09-14 00:44:42
class Solution: def volunteerDeployment(self, finalCnt: List[int], totalNum: int, edges: List[List[int]], plans: List[List[int]]) -> List[int]: dc, finalCnt = defaultdict(list), [1j] + finalCnt for i,j in edges: dc[i].append(j) dc[j].append(i) for i,j in plans[::-1]: v = finalCnt[j] if i==1: finalCnt[j] *= 2 elif i==2: for k in dc[j]: finalCnt[k] -= v else: for k in dc[j]: finalCnt[k] += v sm = sum(finalCnt) i = ((totalNum - sm.real) // sm.imag) if sm.imag else 0 return [int(x.real + x.imag * i) for x in finalCnt]