「一本通 1.1 练习 3」线段

GitHub跳转原题关系图返回列表

按右端点排序后贪心选取互不重合的线段,O(n log n) 求解区间调度。

OJ: roj

题目 ID: 1429

难度:普及-

标签:贪心排序

创建: 2026-09-30 09:54

更新: 2026-10-05 23:32

题目描述

数轴上有 nn 条线段,第 ii 条由整数端点 ai,bia_i, b_i 表示。要求选出尽量大的子集,使得任意两条线段没有重合部分(端点相接不算重合),输出最大条数。输入第一行为 nn,接下来 nn 行每行两个整数 ai,bia_i, b_i。样例输入 3 / 0 2 / 2 4 / 1 3,输出 2。

思路

把所有线段按右端点从小到大排序;维护已选最后一条线段的右端点 last_right,若当前线段左端点 ⩾\geqslant last_right 就选中并更新,否则跳过。

参考代码

Python 版:

python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-30 09:56
# update_at: 2026-09-30 09:56

import sys


def solve() -> None:
    data = iter(map(int, sys.stdin.buffer.read().split()))
    n = next(data)

    segments = sorted(((next(data), next(data)) for _ in range(n)), key=lambda s: s[1])  # 按右端点从小到大排序

    # 贪心:每次选右端点最小且与已选不重叠的线段
    count = 0
    last_right = None  # 已选最后一条线段的右端点
    for left, right in segments:
        not_overlap = last_right is None or left >= last_right  # 端点相接不算重合
        if not_overlap:
            count += 1
            last_right = right

    print(count)


if __name__ == "__main__":
    solve()

C++ 版(同一算法):

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-10-05 23:31
 * update_at: 2026-10-05 23:31
 */
#include <cstdio>
#include <algorithm>

using namespace std;

typedef long long ll;

const int MAXN = 1000005; // 最大线段数

struct Seg {
    ll l, r;
} seg[MAXN];

// 按右端点升序排序
bool cmp(Seg a, Seg b) {
    return a.r < b.r;
}

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%lld %lld", &seg[i].l, &seg[i].r);
    }
    sort(seg + 1, seg + n + 1, cmp);
    int ans = 0;
    ll last_right = -1; // 已选最后一条线段的右端点
    for (int i = 1; i <= n; i++) {
        if (last_right == -1 || seg[i].l >= last_right) {
            ans++;
            last_right = seg[i].r;
        }
    }
    printf("%d\n", ans);
    return 0;
}