撞车
思路
题目在说什么?数轴上有 辆车,第
辆车位于
,速度为
。时刻
时第
辆车在
。如果存在
使得两辆车在同一位置,就会撞车。问最少移除多少辆车才能让剩下的车互不碰撞。
先把所有车按位置从小到大排序。考虑排序后相邻的两辆车 (即
),它们碰撞的条件是什么?
碰撞时刻 ,要求
。因为
,所以需要
,也就是后面的车速度比前面的车慢,前面的车会被追上。
反过来,如果 ,这两辆车永远不会碰撞(速度相等时因为位置不同也不会碰)。
推广到任意两辆车(不只是相邻的),结论一样:排序后,两辆车不碰撞当且仅当速度是非递减的。
所以问题就变成了:排序后,从速度序列中找一个最长非递减子序列,剩下的车都要移除。答案就是 减去这个最长非递减子序列的长度。
最长非递减子序列和 LIS(最长严格递增子序列)的做法几乎一样,只需要把二分查找中的 lower_bound 换成 upper_bound 即可,时间复杂度 。
代码
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<pair<long long,long long>> a(n);
for(int i = 0; i < n; i++){
cin >> a[i].first >> a[i].second;
}
sort(a.begin(), a.end());
// 最长非递减子序列
vector<long long> tails;
for(int i = 0; i < n; i++){
long long v = a[i].second;
auto it = upper_bound(tails.begin(), tails.end(), v);
if(it == tails.end()){
tails.push_back(v);
} else {
*it = v;
}
}
cout << n - (int)tails.size() << endl;
return 0;
}
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine().trim());
long[][] a = new long[n][2];
for (int i = 0; i < n; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
a[i][0] = Long.parseLong(st.nextToken());
a[i][1] = Long.parseLong(st.nextToken());
}
Arrays.sort(a, (x, y) -> Long.compare(x[0], y[0]));
// 最长非递减子序列
List<Long> tails = new ArrayList<>();
for (int i = 0; i < n; i++) {
long v = a[i][1];
int lo = 0, hi = tails.size();
while (lo < hi) {
int mid = (lo + hi) / 2;
if (tails.get(mid) > v) hi = mid;
else lo = mid + 1;
}
if (lo == tails.size()) tails.add(v);
else tails.set(lo, v);
}
System.out.println(n - tails.size());
}
}
import bisect, sys
input = sys.stdin.readline
def main():
n = int(input())
a = []
for _ in range(n):
p, v = map(int, input().split())
a.append((p, v))
a.sort()
tails = []
for _, v in a:
pos = bisect.bisect_right(tails, v)
if pos == len(tails):
tails.append(v)
else:
tails[pos] = v
print(n - len(tails))
main()
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin });
const lines = [];
rl.on('line', l => lines.push(l));
rl.on('close', () => {
const n = parseInt(lines[0]);
const a = [];
for (let i = 1; i <= n; i++) {
const [p, v] = lines[i].split(' ').map(Number);
a.push([p, v]);
}
a.sort((x, y) => x[0] - y[0]);
const tails = [];
for (let i = 0; i < n; i++) {
const v = a[i][1];
let lo = 0, hi = tails.length;
while (lo < hi) {
const mid = (lo + hi) >>> 1;
if (tails[mid] > v) hi = mid;
else lo = mid + 1;
}
if (lo === tails.length) tails.push(v);
else tails[lo] = v;
}
console.log(n - tails.length);
});
复杂度
- 时间复杂度:
,排序
,求最长非递减子序列
。
- 空间复杂度:
。



京公网安备 11010502036488号