首页 > 试题广场 >

撞车

[编程题]撞车
  • 热度指数:1506 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
一条单向单车道的道路上有 n 辆车,第 i 辆车位于 x_i ,速度大小为 v_i

显然,如果车辆保持此速度行驶下去,在大多数情况下都会发生碰撞。

现在牛牛想知道,至少需要移除几辆车,才能让这些车不发生碰撞?

输入描述:
第一行一个整数  ,表示车的数量。

接下来 n 行,每行两个整数 ,表示车的位置和速度的大小。

数据保证 x_i 互不相同。


输出描述:
输出一行一个整数,表示需要移除车的数量。
示例1

输入

3
-1 -1
0 0
1 1

输出

0
示例2

输入

3
-1 1
0 0
1 -1

输出

2
import java.util.*;

public class Main {
    static class Car {
        long x;  // 使用long避免位置值过大导致溢出
        int v;

        Car(long x, int v) {
            this.x = x;
            this.v = v;
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();

        Car[] cars = new Car[n];
        for (int i = 0; i < n; i++) {
            long x = scanner.nextLong();
            int v = scanner.nextInt();
            cars[i] = new Car(x, v);
        }

        // 按位置排序,位置小的车在后面,位置大的车在前面
        Arrays.sort(cars, (a, b) -> Long.compare(a.x, b.x));

        // 提取速度序列
        int[] speeds = new int[n];
        for (int i = 0; i < n; i++) {
            speeds[i] = cars[i].v;
        }

        // 找出最长非递增子序列的长度
        int maxNonIncreasing = longestNonIncreasingSubsequence(speeds);

        // 需要移除的车辆数 = 总车辆数 - 最长非递增子序列的长度
        System.out.println(n - maxNonIncreasing);
    }

    // 计算最长非递增子序列的长度,使用O(n log n)算法
    private static int longestNonIncreasingSubsequence(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }

        List<Integer> tails = new ArrayList<>();

        for (int num : nums) {
            // 找到第一个小于num的位置(二分查找)
            int left = 0, right = tails.size() - 1;
            while (left <= right) {
                int mid = left + (right - left) / 2;
                if (tails.get(mid) <= num) {
                    left = mid + 1;
                } else {
                    right = mid - 1;
                }
            }

            if (left == tails.size()) {
                tails.add(num);
            } else {
                tails.set(left, num);
            }
        }

        return tails.size();
    }
}

发表于 2025-09-23 10:57:13 回复(0)
# 按照位置进行排序
# 将每辆车的速度单独存储成一个数组
# 遍历速度数组元素
# 记录位置排序后的速度最长非递减子序列长度 L
# 满足按 x 升序排列后,速度序列是非递减的,就一定不会撞;否则会撞
# 如果当前速度大于记录窗口中的最大元素则直接添加
# 因为这辆车在之前出现的车后面,并且速度更快一定不会被之前已经出现过的车撞到
# 如果当前车速比tail末尾小,则在tail中找到第一大于v的位置,更新这个位置
# 得到最优最长非递减子序列
# 最后要移除的车的数量为总车数-最长非递减子序列的长度


import sys

def binary_search(arr, target):
    left, right = 0, len(arr)
    while left < right:
        mid = (left + right) // 2
        if arr[mid] > target:
            right = mid
        else:
            left = mid + 1
    return left

def main():
    data = sys.stdin.read().split()
    if not data:
        return
    
    n = int(data[0])
    cars = []
    index = 1
    for i in range(n):
        x = int(data[index])
        v = int(data[index + 1])
        index += 2
        cars.append([x, v])
    
    cars.sort()
    speeds = [car[1] for car in cars]
    
    tail = []
    for v in speeds:
        if not tail&nbs***bsp;v >= tail[-1]:
            tail.append(v)
        else:
            pos = binary_search(tail, v)
            tail[pos] = v
    
    print(n - len(tail))

if __name__ == "__main__":
    main()


发表于 2025-10-11 22:10:51 回复(0)
去求最长不降子序列(相等也要包括),先将输入按照距离进行升序排序之后,遍历数组中的速度使用二分查找找到当前应该插入到子序列的位置(这里让tails[mid]=num[1]也进行left=mid+1使得相等的时候数据进行添加而不是替换)
import java.util.*;
import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        int[][] nums = new int[n][2];
        for (int i = 0; i < n; i++) {
            String[] params = br.readLine().split(" ");
            nums[i][0] = Integer.parseInt(params[0]);
            nums[i][1] = Integer.parseInt(params[1]);
        }
        Arrays.sort(nums, (a, b) -> Integer.compare(a[0], b[0]));
        int len = 0;
        int[] tails = new int[n];
        for (int[] num : nums) {
            int left = 0, right = len;
            while (left < right) {
                int mid = (left + right) / 2;
                if (tails[mid] > num[1]) {
                    right = mid;
                } else {
                    left = mid + 1;
                }
            }
            if (left == len) {
                tails[len++] = num[1];
            } else {
                tails[left] = num[1];
            }
        }
        System.out.print(n - len);
        br.close();
    }
}

发表于 2025-09-19 15:56:06 回复(0)
res=n-最长不严格上升子序列的长度
发表于 2025-07-26 00:32:59 回复(0)