1. 程式人生 > >#10001. 「一本通 1.1 例 2」種樹

#10001. 「一本通 1.1 例 2」種樹

題目題目題目

[題目描述]

某條街被劃為 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;
}

這個就是程式碼,可能有一些會說不通,望大佬指點,蒟蒻太菜了