1423:【例题2】种树
题目描述
现在我们国家开展新农村建设,农村的住房建设纳入了统一规划,统一建设,政府要求每一住户门口种些树。门口路边的地区被分割成块,并被编号成 1..N。每个部分为一个单位尺寸大小并最多可种一棵树。每个居民房子门前被指定了三个号码 B,E,T。这三个数表示该居民想在 B 和 E 之间最少种 T 棵树。当然,B ≤ E,居民必须记住在指定区不能种多于区域地块数的树,所以 T ≤ E-B+1。居民们想种树的各自区域可以交叉。你的任务是求出能满足所有要求的最少的树的数量,尽量减少政府的支出。
输入
第一行包含数据 N,M,区域的个数 (0 < N ≤ 30000),房子的数目 (0 < M ≤ 5000);
接下来的 M 行描述居民们的需要:B E T,0 < B ≤ E ≤ 30000,T ≤ E-B+1。
输出
输出一个数,为满足所有居民的要求,所需要种树的最少数量。
输入样例
9 4
3 5 2
1 4 2
4 6 2
8 9 2
输出样例
5
解决方案与思想
在这道题目中,我们需要在指定的区域内种树,以满足每个居民的需求。每个居民的需求由三个数字 B
、E
和 T
表示,分别代表起始位置、结束位置和需要种的树的数量。我们的目标是尽量减少种树的数量,同时满足所有居民的需求。
为了实现这个目标,我们可以使用贪心算法。贪心算法的核心思想是每一个没有达到需求的居民都从结束位置向前种,这样能尽可能同时满足其他人的需求。具体步骤如下:
- 按区域结束时间排序:首先将所有需求按结束时间升序排序。
- 选择种树:从第一个需求开始,依次选择满足需求且种树数量最少的区域。
通过这种方式,我们可以确保在满足所有居民需求的前提下,尽量减少种树的数量。
代码实现
以下是完整的代码实现:
#include <bits/stdc++.h>
using namespace std;
// 定义三元组结构体
struct triple {
int first;
int second;
int third;
};
// 自定义比较函数,用于按区域结束时间排序
bool cmp(const triple& a, const triple& b) {
return a.second < b.second;
}
int main() {
int n, m;
cin >> n >> m; // 输入区域的个数和房子的数目
vector<triple> v1; // 存储每个居民的需求
vector<int> v2(n + 1, 0); // 记录每个区域是否种了树
int num = 0; // 记录最少需要种的树的数量
// 输入每个居民的需求
for (int i = 0; i < m; i++) {
int f, s, t;
cin >> f >> s >> t;
v1.push_back({f, s, t});
}
// 按区域结束时间排序
sort(v1.begin(), v1.end(), cmp);
// 贪心算法选择种树
for (auto it = v1.begin(); it != v1.end(); it++) {
int curtree = 0;
// 计算当前区域已经种了多少棵树
for (int i = it->first; i <= it->second; i++) {
if (v2[i] == 1)
curtree++;
}
// 如果已经满足需求,跳过
if (curtree >= it->third) {
continue;
}
// 否则,从右向左种树,直到满足需求
for (int i = it->second; i >= it->first && curtree < it->third; i--) {
if (v2[i] == 0) {
curtree++;
num++;
v2[i] = 1;
}
}
}
// 输出最少需要种的树的数量
cout << num << endl;
return 0;
}