【问题描述】 有n个单位宽度的木板,每块木板的长度是Li.每块木板中间都有一个空槽,空槽必须挂在Pi处的钉子上,如图10. 4-1所示。 带空槽的木板钉子5 图10. 4-1 木板与钉子移动示意图 现在,要选出尽可能多的木板并且将他们安排在一个直线上,使得没有两块木板相交(一个包含另外一个当然也是禁止的,不过边界相碰是允许的)。空槽两端忽略不计,钉子也非常细,可以安置在木板的边界,就是说木板的左端点的可能位置是Pi-Li至Pi.没有两颗钉子在同一个 位置。 【输入格式】 第1行1个正整数n,代表木板的数量(1≤n≤100000). 接下来的每一行包含两个正整数Li和Pi(1≤Li、Pi≤10000000),代表第i块木板的长度,以及相关的钉子的位置。 【输出格式】 输出一行一个整数,代表可以选择的最多的木板。 【输入样例】 7 5 9 2 17 6 10 3 11 2 16 4 13 5 6 【输出样例】 5 【数据限制】 对于20%的数据满足:n≤15. 对于50%的数据满足:n≤1000. 对于100%的数据满足:1≤n≤100000.
时间: 2024-04-18 19:32:13 浏览: 341
这是一个经典的贪心算法问题。我们可以按照木板的右端点位置进行排序,然后从左到右依次选择木板,保证每次选择的木板不与前面已选择的木板相交。
具体的解题思路如下:
1. 将输入的木板按照右端点位置Pi进行排序。
2. 初始化一个变量count,表示选择的木板数量,初始值为1(至少选择一块木板)。
3. 初始化一个变量end,表示当前已选择的木板的最右端点位置,初始值为第一块木板的右端点位置P1。
4. 从第二块木板开始遍历,对于每一块木板:
- 如果该木板的左端点位置Li大于end,表示该木板可以选择,更新count和end,count加1,end更新为该木板的右端点位置Pi。
- 如果该木板的左端点位置Li小于等于end,表示该木板与前面已选择的木板相交,不选择该木板。
5. 输出count,即为可以选择的最多的木板数量。
以下是C++代码实现示例:
```cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Board {
int length;
int position;
};
bool compare(Board b1, Board b2) {
return b1.position < b2.position;
}
int selectBoards(vector<Board>& boards) {
sort(boards.begin(), boards.end(), compare);
int count = 1;
int end = boards[0].position;
for (int i = 1; i < boards.size(); i++) {
if (boards[i].position > end) {
count++;
end = boards[i].position;
}
}
return count;
}
int main() {
int n;
cin >> n;
vector<Board> boards(n);
for (int i = 0; i < n; i++) {
cin >> boards[i].length >> boards[i].position;
}
int result = selectBoards(boards);
cout << result << endl;
return 0;
}
```
输入示例:
```
7
5 9
2 17
6 10
3 11
2 16
4 13
5 6
```
输出示例:
```
5
```
该代码的时间复杂度为O(nlogn),其中n为木板的数量。
阅读全文