#10001. 「一本通 1.1 例 2」种树

版权声明:有女朋友的老江的博客,转载请告知老江 https://blog.csdn.net/qq_42367531/article/details/83447152

题目题目题目

[题目描述]

某条街被划为 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;
}

这个就是代码,可能有一些会说不通,望大佬指点,蒟蒻太菜了 

猜你喜欢

转载自blog.csdn.net/qq_42367531/article/details/83447152
今日推荐