2532.过桥的时间
链接:2532.过桥的时间
难度:Hard
标签:数组、模拟、堆(优先队列)
简介:所有 n 个盒子都需要放入新仓库,请你返回最后一个搬运箱子的工人 到达河左岸 的时间。
题解 1 - rust
- 编辑时间:2023-01-08
- 执行用时:36ms
- 内存消耗:3.6MB
- 编程语言:rust
- 解法介绍:同上。
use std::{cmp::Ordering, collections::BinaryHeap};
#[derive(Eq, Ord, PartialEq)]
struct Worker {
    i: i32,
    l2r: i32,
    pick_old: i32,
    r2l: i32,
    put_new: i32,
    wait: i32,
    mode: bool,
}
impl Worker {
    fn new(i: i32, l2r: i32, pick_old: i32, r2l: i32, put_new: i32) -> Self {
        Worker {
            i,
            l2r,
            pick_old,
            r2l,
            put_new,
            wait: 0,
            mode: true,
        }
    }
    fn cost(&self) -> i32 {
        self.l2r + self.r2l
    }
    fn cmp(&self, worker: &Worker) -> Ordering {
        if self.mode {
            self.cmp_bridge(worker)
        } else {
            self.cmp_wait(worker)
        }
    }
    fn cmp_bridge(&self, worker: &Worker) -> Ordering {
        if self.cost() != worker.cost() {
            self.cost().cmp(&worker.cost())
        } else {
            self.i.cmp(&worker.i)
        }
    }
    fn cmp_wait(&self, worker: &Worker) -> Ordering {
        worker.wait.cmp(&self.wait)
    }
    fn set_mode(&mut self, mode: bool) {
        self.mode = mode;
    }
    fn set_bridge_mode(&mut self) {
        self.set_mode(true)
    }
    fn set_wait_mode(&mut self) {
        self.set_mode(false)
    }
}
impl ToString for Worker {
    fn to_string(&self) -> String {
        return format!(
            "Worker{}: l2r = {}, r2l = {}, pickOld = {}, putNew = {}, cost = {}, wait = {}",
            self.i,
            self.l2r,
            self.r2l,
            self.pick_old,
            self.put_new,
            self.cost(),
            self.wait
        );
    }
}
impl PartialOrd for Worker {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}
fn printHeap(name: &'static str, heap: &BinaryHeap<Worker>) {
    println!("=> {name}({})", heap.len());
    for item in heap.iter() {
        println!("{}", item.to_string());
    }
}
impl Solution {
    pub fn find_crossing_time(n: i32, k: i32, time: Vec<Vec<i32>>) -> i32 {
        let mut n = n;
        let mut workers = Vec::new();
        for i in 0..time.len() {
            workers.push(Worker::new(
                i as i32, time[i][0], time[i][1], time[i][2], time[i][3],
            ));
        }
        let mut left_heap = BinaryHeap::<Worker>::new();
        let mut right_heap = BinaryHeap::<Worker>::new();
        let mut pick_heap = BinaryHeap::<Worker>::new();
        let mut put_heap = BinaryHeap::<Worker>::new();
        for worker in workers {
            left_heap.push(worker);
        }
        let mut ans = 0;
        while n > 0 {
            // println!("====loop====");
            // println!("ans = {ans}, n = {n}");
            // printHeap("left_heap", &left_heap);
            // printHeap("right_heap", &right_heap);
            // printHeap("pick_heap", &pick_heap);
            // printHeap("put_heap", &put_heap);
            while !pick_heap.is_empty() && pick_heap.peek().unwrap().wait <= ans {
                let mut worker = pick_heap.pop().unwrap();
                worker.set_bridge_mode();
                right_heap.push(worker);
            }
            while !put_heap.is_empty() && put_heap.peek().unwrap().wait <= ans {
                let mut worker = put_heap.pop().unwrap();
                worker.set_bridge_mode();
                left_heap.push(worker);
            }
            if left_heap.is_empty() && right_heap.is_empty() {
                let pick = match pick_heap.peek() {
                    Some(worker) => worker.wait,
                    None => i32::MAX,
                };
                let put = match put_heap.peek() {
                    Some(worker) => worker.wait,
                    None => i32::MAX,
                };
                ans = pick.min(put);
            }
            if !right_heap.is_empty() {
                let mut worker = right_heap.pop().unwrap();
                ans += worker.r2l;
                worker.wait = ans + worker.put_new;
                worker.set_wait_mode();
                put_heap.push(worker);
            } else if !left_heap.is_empty() && n > 0 {
                let mut worker = left_heap.pop().unwrap();
                ans += worker.l2r;
                worker.wait = ans + worker.pick_old;
                worker.set_wait_mode();
                pick_heap.push(worker);
                n -= 1;
            }
        }
        while !right_heap.is_empty() || !pick_heap.is_empty() {
            // println!("====after====");
            // println!("ans = {ans}, n = {n}");
            // printHeap("left_heap", &left_heap);
            // printHeap("right_heap", &right_heap);
            // printHeap("pick_heap", &pick_heap);
            // printHeap("put_heap", &put_heap);
            if !right_heap.is_empty() {
                ans += right_heap.pop().unwrap().r2l;
            }
            while !pick_heap.is_empty() && pick_heap.peek().unwrap().wait <= ans {
                let mut worker = pick_heap.pop().unwrap();
                worker.set_bridge_mode();
                right_heap.push(worker);
            }
            if right_heap.is_empty() && !pick_heap.is_empty() {
                ans = pick_heap.peek().unwrap().wait;
            }
        }
        ans
    }
}
题解 2 - cpp
- 编辑时间:2023-07-07
- 执行用时:188ms
- 内存消耗:20.5MB
- 编程语言:cpp
- 解法介绍:模拟。
#define X first
#define Y second
class Solution {
public:
    typedef pair<int, int> pii;
    int findCrossingTime(int n, int k, vector<vector<int>>& time) {
        auto cmp = [&](int i1, int i2) {
            int v1 = time[i1][0] + time[i1][2], v2 = time[i2][0] + time[i2][2];
            return v1 < v2 || v1 == v2 && i1 < i2;
        };
        priority_queue<int, vector<int>, decltype(cmp)> ql(cmp), qr(cmp);
        for (int i = 0; i < k; i++) ql.push(i);
        auto cmpp = [&](pii i1, pii i2) {
            return i2.X < i1.X;
        };
        priority_queue<pii, vector<pii>, decltype(cmpp)> qpl(cmpp), qpr(cmpp);
        int res = 0;
        while (qr.size() || qpr.size() || n > 0) {
            // cout << "===> Loop: " 
            //      << "n = " << n
            //      << ", res = " << res
            //      << ", qpl = " << (qpl.size() ? (long long)qpl.top().X * 100 + qpl.top().Y : -1)
            //      << ", ql = " << (ql.size() ? ql.top() : -1)
            //      << ", qr = " << (qr.size() ? qr.top() : -1)
            //      << ", qpr = " << (qpr.size() ? (long long)qpr.top().X * 100 + qpr.top().Y : -1)
            //      << endl;
            if ((ql.empty() && qr.empty()) || qr.empty() && qpr.size() && n == 0) {
                res = max(
                    res,
                    min(
                        qpl.size() ? qpl.top().X : INT_MAX,
                        qpr.size() ? qpr.top().X : INT_MAX
                    )
                );
            }
            while (qpl.size() && qpl.top().X <= res) {
                auto cur = qpl.top();
                qpl.pop();
                ql.push(cur.Y);
            }
            while (qpr.size() && qpr.top().X <= res) {
                auto cur = qpr.top();
                qpr.pop();
                qr.push(cur.Y);
            }
            if (qr.size()) {
                auto cur = qr.top();
                qr.pop();
                res += time[cur][2];
                qpl.push(make_pair(res + time[cur][3], cur));
            } else if (ql.size() && n > 0) {
                n -= 1;
                auto cur = ql.top();
                ql.pop();
                res += time[cur][0];
                qpr.push(make_pair(res + time[cur][1], cur));
            }
        }
        return res;
    }
};
题解 3 - typescript
- 编辑时间:2023-01-08
- 执行用时:276ms
- 内存消耗:53MB
- 编程语言:typescript
- 解法介绍:模拟。
class Heap<T = number> {
  public arr: T[] = [];
  get isEmpty() {
    return this.size === 0;
  }
  get size() {
    return this.arr.length;
  }
  get top() {
    return this.arr[0];
  }
  constructor(public compare: (t1: T, t2: T) => number) {}
  add(num: T): void {
    this.arr.push(num);
    this.shiftUp(this.size - 1);
  }
  remove(): T {
    const num = this.arr.shift()!;
    if (this.size) {
      this.arr.unshift(this.arr.pop()!);
      this.shiftDown(0);
    }
    return num;
  }
  private shiftUp(index: number): void {
    if (index === 0) return;
    const parentIndex = (index - 1) >> 1;
    if (this.compare(this.arr[index], this.arr[parentIndex]) > 0) {
      [this.arr[index], this.arr[parentIndex]] = [this.arr[parentIndex], this.arr[index]];
      this.shiftUp(parentIndex);
    }
  }
  private shiftDown(index: number): void {
    let childrenIndex = index * 2 + 1;
    if (childrenIndex > this.size - 1) return;
    if (
      childrenIndex + 1 <= this.size - 1 &&
      this.compare(this.arr[childrenIndex + 1], this.arr[childrenIndex]) > 0
    ) {
      childrenIndex++;
    }
    if (this.compare(this.arr[childrenIndex], this.arr[index]) > 0) {
      [this.arr[childrenIndex], this.arr[index]] = [this.arr[index], this.arr[childrenIndex]];
      this.shiftDown(childrenIndex);
    }
  }
  *[Symbol.iterator](): IterableIterator<T> {
    for (const t of this.arr) {
      yield t;
    }
  }
}
class TWorker {
  constructor(
    public i: number,
    public l2r: number,
    public pickOld: number,
    public r2l: number,
    public putNew: number,
    public wait: number = 0
  ) {}
  cost() {
    return this.l2r + this.r2l;
  }
  cmp(worker: TWorker) {
    return this.cost() !== worker.cost() ? this.cost() - worker.cost() : this.i - worker.i;
  }
  cmpWait(worker: TWorker) {
    return worker.wait - this.wait;
  }
  toString() {
    return `Worker${this.i}: l2r=${this.l2r}, r2l=${this.r2l}, pickOld=${this.pickOld}, putNew=${
      this.putNew
    }, cost=${this.cost()}, wait = ${this.wait}`;
  }
}
function findCrossingTime(n: number, k: number, time: number[][]): number {
  const workers = new Array(k)
    .fill(0)
    .map((_, i) => new TWorker(i, ...(time[i] as [number, number, number, number])));
  console.log('========');
  console.log(workers.map(v => v.toString()).join('
'));
  console.log('========');
  const lHeap = new Heap<TWorker>((w1, w2) => w1.cmp(w2));
  const rHeap = new Heap<TWorker>((w1, w2) => w1.cmp(w2));
  const pickHeap = new Heap<TWorker>((t1, t2) => t1.cmpWait(t2));
  const putHeap = new Heap<TWorker>((t1, t2) => t1.cmpWait(t2));
  const printHeap = (record: Record<string, Heap<TWorker>>) =>
    Object.entries(record).forEach(([k, v]) =>
      console.log(`=> ${k}(${v.size}):
${v.arr.map(v => v.toString()).join('
')}`)
    );
  for (const worker of workers) lHeap.add(worker);
  let ans = 0;
  while (n) {
    console.log('=====loop====');
    console.log(`ans = ${ans}, n = ${n}`);
    printHeap({ lHeap, rHeap, pickHeap, putHeap });
    while (pickHeap.size && pickHeap.top.wait <= ans) rHeap.add(pickHeap.remove());
    while (putHeap.size && putHeap.top.wait <= ans) lHeap.add(putHeap.remove());
    if (lHeap.isEmpty && rHeap.isEmpty) {
      const pick = pickHeap.top?.wait ?? Infinity;
      const put = putHeap.top?.wait ?? Infinity;
      if (pick < put) ans = pickHeap.top.wait;
      else ans = putHeap.top.wait;
      while (pickHeap.size && pickHeap.top[0] <= ans) rHeap.add(pickHeap.remove()), n--;
      while (putHeap.size && putHeap.top[0] <= ans) lHeap.add(putHeap.remove());
    }
    if (rHeap.size) {
      ans += rHeap.top.r2l;
      const worker = rHeap.remove();
      worker.wait = ans + worker.putNew;
      putHeap.add(worker);
    } else if (lHeap.size && n) {
      ans += lHeap.top.l2r;
      const worker = lHeap.remove();
      worker.wait = ans + worker.pickOld;
      pickHeap.add(worker);
      n--;
    }
  }
  while (rHeap.size || pickHeap.size) {
    console.log('=====after====');
    console.log(`ans = ${ans}, n = ${n}`);
    printHeap({ lHeap, rHeap, pickHeap, putHeap });
    if (rHeap.size) ans += rHeap.remove().r2l;
    while (pickHeap.size && pickHeap.top.wait <= ans) rHeap.add(pickHeap.remove());
    if (rHeap.isEmpty && pickHeap.size) ans = pickHeap.top.wait;
  }
  return ans;
}