列表

详情


LCP 46. 志愿者调配

「力扣挑战赛」有 n 个比赛场馆(场馆编号从 0 开始),场馆之间的通道分布情况记录于二维数组 edges 中,edges[i]= [x, y] 表示第 i 条通道连接场馆 x 和场馆 y(即两个场馆相邻)。初始每个场馆中都有一定人数的志愿者(不同场馆人数可能不同),后续 m 天每天均会根据赛事热度进行志愿者人数调配。调配方案分为如下三种:

  1. 将编号为 idx 的场馆内的志愿者人数减半;
  2. 将编号为 idx 的场馆相邻的场馆的志愿者人数都加上编号为 idx 的场馆的志愿者人数;
  3. 将编号为 idx 的场馆相邻的场馆的志愿者人数都减去编号为 idx 的场馆的志愿者人数。

所有的调配信息记录于数组 plans 中,plans[i] = [num,idx] 表示第 i 天对编号 idx 的场馆执行了第 num 种调配方案。 在比赛结束后对调配方案进行复盘时,不慎将第 0 个场馆的最终志愿者人数丢失,只保留了初始所有场馆的志愿者总人数 totalNum ,以及记录了第 1 ~ n-1 个场馆的最终志愿者人数的一维数组 finalCnt。请你根据现有的信息求出初始每个场馆的志愿者人数,并按场馆编号顺序返回志愿者人数列表。

注意:

示例 1:

image.png 输入: finalCnt = [1,16], totalNum = 21, edges = [[0,1],[1,2]], plans = [[2,1],[1,0],[3,0]]

输出:[5,7,9]

解释: image.png{: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]

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: vector<int> volunteerDeployment(vector<int>& finalCnt, long long totalNum, vector<vector<int>>& edges, vector<vector<int>>& plans) { } };

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]

上一题