NC25136 [USACO 2006 Ope B]Cows on a Leash

题目

题目描述

给定如图所示的若干个长条。你可以在某一行的任意两个数之间作一条竖线,从而把这个长条切开,并可能切开其他长条。问至少要切几刀才能把每一根长条都切开。样例如图需要切两刀。
img
注意:输入文件每行的第一个数表示开始的位置,而第二个数表示长度。

输入描述

Line \(1\) : A single integer, \(N\) (\(2 <= N <= 32000\))
Lines \(2 \cdots N+1\): Each line contains two space-separated positive integers that describe a leash. The first is the location of the leash's stake; the second is the length of the leash.(\(1 <= length <= 1e7\))

输出描述

Line \(1\) : A single integer that is the minimum number of cuts so that each leash is cut at least once.

示例1

输入

7
2 4
4 7
3 3
5 3
9 4
1 5
7 3

输出

2

题解

知识点:排序,贪心。

我们希望每次分割的时候能分割最多的段,并且希望这个分割位置容易找到。

排序各行相对情况不影响结果,考虑以右端点从小到大排序,并从左到右切。而此时如果选择切一条带子,假设前面的带子已经切过了,切在带子最右端是最好的,因为后面的带子如果能切到一定与这条带子右端点有交集,从而选择最右端能最大化。

然后找到后面一条不能切到的带子重复操作,得到最小切割数。

注意:这里要切在两个数中间,因此注意下一次允许切割段从这段的右端点坐标开始。

当然这道题也可以理解为安排活动问题,找到最多不重合的区间,就是最终答案。

时间复杂度 \(O(n \log n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>

using namespace std;

pair<int, int> a[32007];

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    for (int i = 0;i < n;i++) cin >> a[i].first >> a[i].second, a[i].second += a[i].first;
    sort(a, a + n, [&](pair<int, int> a, pair<int, int> b) {return a.second == b.second ? a.first < b.first : a.second < b.second;});
    int cnt = 0, last = 0;
    for (int i = 0;i < n;i++) {
        if (last <= a[i].first) {
            cnt++;
            last = a[i].second;
        }
    }
    cout << cnt << '\n';
    return 0;
}
posted @ 2022-06-15 23:13  空白菌  阅读(59)  评论(0编辑  收藏  举报