Post

CF1841D Pairs of Segments

CF1841D Pairs of Segments

这篇博客主要讲述了一个算法问题,题目是给定 $n$ 条线段,每对线段由两个相交的线段组成。要求删除最少的线段,使得剩余的线段可以分成若干对,且每对线段互不相交。文章通过贪心算法解决这个问题,具体实现代码也给出了。

题目大意

有 $n$ 条线段,一对线段由两个相交线段组成。

称某 $k$ 条线段为漂亮的线段组,如果 $k$ 条线段满足:

  • $k$ 是偶数
  • 可以分成 $k/2$ 对线段,且不同对线段中的线段各不相交

问最少删去多少条线段可以使这 $n$ 条线段是漂亮的。

思路

先 $O(n^2)$ 的处理出所有可能出现的线段对,每个线段对可以合成一条新的线段。在这些新线段中选取一些互不相交的线段,互不相交的线段数量即为漂亮线段组中线段数的一半。

问题即转化为经典的选择不相交区间问题:给出一堆区间,要求选择尽量多的区间,使得这些区间互不相交,求可选取的区间的最大数量。这里端点相同也算有重复。

贪心的解决这类问题,将这些线段右端点从小到大排序,每次选择与前面选择的线段不相交的线段。贪心正确性显然。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
struct sgm {
    int l, r;
};
bool cmp(sgm x, sgm y) {
    return x.r < y.r;
    //    return x.l > y.l;
}
bool is_pair(sgm x, sgm y) {
    return (x.l >= y.l && x.l <= y.r) || (x.r >= y.l && x.r <= y.r);
}
sgm a[2010], u[4000010];
int n, res, tot;
void solve() {
    tot = 0;
    cin >> n;
    rep(i, 0, n - 1) cin >> a[i].l >> a[i].r;
    rep(i, 0, n - 1) rep(j, i + 1, n - 1) {
        if (is_pair(a[i], a[j]) || is_pair(a[j], a[i]))
            u[tot++] = sgm{min(a[i].l, a[j].l), max(a[i].r, a[j].r)};
    }
    if (tot == 0) {
        cout << n << endl;
        return;
    }
    sort(u, u + tot, cmp);
    sgm tmp = u[0];
    res = 1;
    rep(i, 1, tot - 1) {
        if (!is_pair(tmp, u[i]) && !is_pair(u[i], tmp)) {
            res++;
            tmp = u[i];
        }
    }
    cout << n - 2 * res << endl;
}
This post is licensed under CC BY 4.0 by the author.