解题思路
按照需求路段的结束位置升序排列,然后检查需求路段内已种树木数量,如果没有种满,依次从结束位置开始种树,直到种满,检查下一路段。最后输出种植的树木棵数。
为什么要按结束位置升序排列:我们知道,如果对于任意两段终点相同的道路,必然有其中一条路段完全包含于另一条路段(重合比例为100%)。而对于一般情况,当两个路段结束位置距离越小,两个路段重合的比例越大。按照结束位置升序编号后,任意相邻编号路段满足结束位置相差最小(相比其他所有路段),重合比例最大,因此更有可能种更少的树满足要求。
下面是一些重点片段:
1.定义结构体 info
:
struct info {
int st; // 起始路段
int ed; // 结束路段
int num; // 需求树木数量
};
2.定义比较函数 cmp
:
bool cmp(const info &a, const info &b) {
return (a.ed < b.ed);
}
3.定义数组 road
和主函数:
bool road[30005] = {0};
int main() {
// ...
}
road
是一个布尔数组,用于记录每个路段是否已经种植了树木的情况。数组大小为 30005,根据题目描述,路段数最多为 30000。
4.初始化变量 cont
为 0,用于记录种植的树木总数;遍历每个建议,判断并种植树木:
int cont = 0;
for (int i = 0; i < m; i++) {
int sum = 0;
for (int j = task[i].ed; j >= task[i].st; j--)
if (road[j] == 1)
sum++;
if (sum < task[i].num) {
for (int j = task[i].ed; j >= task[i].st; j--) {
if (road[j] == 0) {
road[j] = 1;
cont++;
sum++;
}
if (sum == task[i].num)
break;
}
}
}
参考代码
#include <iostream>
#include <algorithm>
using namespace std;
struct info
{
int st;
int ed;
int num;
};
bool cmp(const info& a, const info& b)
{
return (a.ed < b.ed);
}
bool road[30005] = {0};
int main()
{
int n, m;
cin >> n >> m;
info task[5005] = {0};
for(int i = 0; i < m; i++)
{
cin >> task[i].st >> task[i].ed >> task[i].num;
}
sort(task, task+m, cmp);
int cont = 0;
for(int i = 0; i < m; i++)
{
int sum = 0;
for(int j = task[i].ed; j >= task[i].st; j--)
if(road[j] == 1)
sum++;
if(sum < task[i].num)
{
for(int j = task[i].ed; j >= task[i].st; j--)
{
if(road[j] == 0)
{
road[j] = 1;
cont++;
sum++;
}
if(sum == task[i].num)
break;
}
}
}
cout << cont;
return 0;
}