[题目描述]
某条街被划为 n条路段,这 n 条路段依次编号为 1…n。每个路段最多可以种一棵树。现在居民们给出了 hhh 组建议,每组建议包含三个整数 b,e,t,表示居民希望在路段 b 到 e 之间至少要种 t 棵树。这些建议所给路段的区间可以交叉。请问:如果要满足所有居民的建议,至少要种多少棵树。
[输入格式]
第一行为 n,表示路段数。
第二行为 h,表示建议数。
下面 h行描述一条建议:b,e,t,用一个空格分隔。
[输出格式]
输出只有一个数,为满足所有居民的建议,所需要种树的最少数量。
[样例输入]
9
4
1 4 2
4 6 2
8 9 2
3 5 2
[样例输出]
5
[数据范围与提示]
30%的数据满足 0<n≤1000,0<h≤5000;
100%的数据满足 0<n≤3×10^4,h≤5000,0<b≤e≤3×10^4,t≤e−b+1
思路:莫名想用黑色写我也不知道为什么,这道题的题目其实已经解释的很清楚要用贪心了,因为我们要求的是最优解,所以贪心自然就是最好的交代了。然后就看代码吧,思路我在代码里面也有详细的提及。
1.先按结束位置从小到大排序
2.对每个区间依次处理
a.从前到后扫描这个区间,统计已选点的个数
b.若已选点的个数超过了要求的点数,则continue
c.否则从该区间由后向前扫描,添加缺少的覆盖点
【代码实现】
/*
种树这道题是一道贪心题,因为题目要求的是最小值
那么第一时间想到的一定是贪心,因为要求的是最优解
同时,这道题有一个区间,求区间内的最小值
(有没有一看到就会想到区间dp)
但是不一定要是区间dp,也可以用贪心来尝试
因为dp和贪心都是求最优解的一种办法
(我是一个不正道的人,既然这一章节是关于贪心,那就贪心吧,QAQ)
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
/*
定义结构体的作用我貌似在活动安排提及了一下,定义结构体就是为了排序
要求最优解,就是有一个不断走最有的一步的过程
所以排序起到很重要的作用
如果不是结构体排序的话,会导致两两对不上,那么答案必然出错
*/
{
int x,y,c;//x-y表示要求的这段路,c表示要种的树的数量
}a[210000];
int n,m;
bool v[210000];//
bool cmp(node n1,node n2)//结构体排序不解释
{
if(n1.y>n2.y) return false;//算了解释一下吧(我强迫症),如果是前面一个大于后面一个就不成立
else return true;//如果后面一个大于前面一个就成立
//这是用x-y这一段路的结尾来排序,目的下面解释
}
int main()
{
scanf("%d%d",&n,&m);//输入
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].c);//输入
}
sort(a+1,a+m+1,cmp);
/*
排序,之所以要用路段的结尾来排序,就是为了不漏掉要种的数
比如说:
1-3
1-5
1-8
如果我们种了8这棵树的话,只能兼顾到 1-8
但是如果我们种 1或者2或者3的话,那我们三组都可以兼顾
如果我们种 6或者7的话,就只能兼顾 1-8
所以这就是贪心
就是为了每一步都可以做到最好,兼顾到最多
*/
int ans=0; memset(v,false,sizeof(v));
//ans是用来保存最少的种树量 //v数组是用来判断当前的位置有没有种过树
for(int i=1;i<=m;i++)
{
int t=0;//这是记录当前还可以种的树的数量,t每一次循环都会等于0
for(int j=a[i].x;j<=a[i].y;j++)
if(v[j]==true)
t++;
//这个就是枚举区间范围内,如果可以种的话,t增加1
if(t>=a[i].c) continue;//如果种的数大于了要求种的树之后,
//就执行for(int i=1;i<=m;i++)否则接着下面
for(int j=a[i].y;j>=a[i].x;j--)
//前面是从前往后,现在是从后往前,防止漏掉
{
if(v[j]!=true)//如果当前的这个是没有种过的
{
t++;//就增加一棵可以种的数
ans++;//然后ans++
v[j]=true;//把这个记录成种过的
if(t==a[i].c) break;//当t的数量达到了要求的数量之后,退出输出答案
}
}
}
printf("%d\n",ans);//输出
return 0;
}
这个就是代码,可能有一些会说不通,望大佬指点,蒟蒻太菜了