#[derive(Debug, Clone)]
pub struct WeightedInterval {
pub start: usize,
pub end: usize,
pub weight: u64,
}
impl WeightedInterval {
pub fn new(start: usize, end: usize, weight: u64) -> Self {
assert!(start <= end, "start cannot be greater than end");
Self { start, end, weight }
}
}
pub fn max_weighted_schedule(intervals: &[WeightedInterval]) -> usize {
if intervals.is_empty() {
return 0;
}
let mut sorted = intervals.to_vec();
sorted.sort_by_key(|iv| iv.end);
let p = compute_predecessors(&sorted);
let n = sorted.len();
let mut dp = vec![0_u64; n + 1];
for i in 1..=n {
let weight_i = sorted[i - 1].weight;
let p_i = p[i - 1];
let pred_dp = if p_i >= 0 { dp[p_i as usize + 1] } else { 0 };
dp[i] = dp[i - 1].max(weight_i + pred_dp);
}
dp[n] as usize
}
pub fn best_weighted_schedule(intervals: &[WeightedInterval]) -> Vec<WeightedInterval> {
if intervals.is_empty() {
return Vec::new();
}
let mut sorted = intervals.to_vec();
sorted.sort_by_key(|iv| iv.end);
let p = compute_predecessors(&sorted);
let n = sorted.len();
let mut dp = vec![0_u64; n + 1];
let mut chosen = vec![false; n];
for i in 1..=n {
let weight_i = sorted[i - 1].weight;
let p_i = p[i - 1];
let pred_dp = if p_i >= 0 { dp[p_i as usize + 1] } else { 0 };
let with_current = weight_i + pred_dp;
let without_current = dp[i - 1];
if with_current > without_current {
dp[i] = with_current;
chosen[i - 1] = true;
} else {
dp[i] = without_current;
}
}
let mut result = Vec::new();
let mut i = n;
while i > 0 {
if chosen[i - 1] {
result.push(sorted[i - 1].clone());
i = if p[i - 1] >= 0 {
(p[i - 1] as usize) + 1
} else {
0
};
} else {
i -= 1;
}
}
result.reverse();
result
}
fn compute_predecessors(intervals: &[WeightedInterval]) -> Vec<isize> {
let n = intervals.len();
let mut p = vec![-1; n];
for i in 0..n {
let start_i = intervals[i].start;
let mut lo = 0_usize;
let mut hi = i;
while lo < hi {
let mid = (lo + hi) / 2;
if intervals[mid].end <= start_i {
lo = mid + 1;
} else {
hi = mid;
}
}
if lo > 0 {
p[i] = (lo - 1) as isize;
} else {
p[i] = -1;
}
}
p
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_max_weighted_schedule_basic() {
let intervals = vec![
WeightedInterval::new(0, 3, 4),
WeightedInterval::new(1, 5, 2),
WeightedInterval::new(4, 6, 5),
WeightedInterval::new(5, 9, 6),
];
assert_eq!(max_weighted_schedule(&intervals), 10);
}
#[test]
fn test_best_weighted_schedule_basic() {
let intervals = vec![
WeightedInterval::new(0, 3, 4),
WeightedInterval::new(1, 5, 2),
WeightedInterval::new(4, 6, 5),
WeightedInterval::new(5, 9, 6),
];
let result = best_weighted_schedule(&intervals);
let total_weight: u64 = result.iter().map(|iv| iv.weight).sum();
assert_eq!(total_weight, 10);
for i in 0..result.len() {
for j in i + 1..result.len() {
assert!(result[i].end <= result[j].start || result[j].end <= result[i].start);
}
}
}
#[test]
fn test_edge_cases() {
let intervals: Vec<WeightedInterval> = vec![];
assert_eq!(max_weighted_schedule(&intervals), 0);
assert!(best_weighted_schedule(&intervals).is_empty());
let intervals = vec![WeightedInterval::new(2, 4, 10)];
assert_eq!(max_weighted_schedule(&intervals), 10);
let result = best_weighted_schedule(&intervals);
assert_eq!(result.len(), 1);
assert_eq!(result[0].weight, 10);
}
}