2014NOIP複賽模擬練習 設置噴水池 解題報告

【問題描述】  
  
  笑笑家的樓下是一條綠化帶,可以用一條從0到10000的線段來表示。笑笑還知道這個綠化帶上有n個地點(座標爲0到10000的整數)可以設置噴水池。已知噴水池的半徑爲r(正整數)。笑笑希望知道至少需要設置多少個噴水池才能把這個綠化帶完全灌溉。
 
    
 【輸入格式】  
  
  第 1 行:兩個整數n和r,分別表示可以設置噴水池的地點和噴水池的半徑。
  第 2 行:有n個數,分別表示可設置噴水池的地點座標


 
    
 【輸出格式】  
   
  一個數,表示需要設置的噴水池的最少數量。
 
    
 【輸入樣例】   
   
5 4000
0 1000 3000 2000 9000


 
    
 【輸出樣例】  
   
2
 
    
 【數據範圍】  
   
n<=1000,可以保證不存在無解情況。

 


解題思路:根據題意,每個噴水池都有一個座標和相同的半徑,因此可以將每個噴水池的噴水區域看作一條線段(一個區間),而綠化帶是一條0-10000的線段([0,10000]),於是該題轉化爲區間覆蓋問題,要求設置的噴水池的最少數量,即是求選擇最少的線段(區間)去覆蓋綠化帶。求區間覆蓋問題,可以使用貪心算法,將每條線段按左端點由小到大排序,假設要覆蓋區間[s,t],首先在c[i].a(線段的左端點)<=s中,找一個c[i].b(線段的右端點)最大的,將s改爲最大的c[i].b繼續重複上述操作,最後所選的線段數即爲答案。需要注意的是,在存每個噴水池的噴水區域時,噴水區域的範圍是[0,10000]。


#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
const int maxn=1005;
int N,R;
int A[maxn];
struct data
{
	int a,b;
};
data c[maxn];
bool cmp(data aa,data bb)
{
	return aa.a<bb.a;
}
void solve()  //解決區間覆蓋問題
{
	int s=0,t=10000,cnt=0,i=1;
	while(i<=N && s<t)
	{
		int now=0;
		while(i<=N && c[i].a<=s)
		{
			if(c[i].b>now)  now=c[i].b;  //找到滿足條件的最大的線段的右端點
			i++;
		}
		cnt++;
		s=now;
	}
	printf("%d\n",cnt);
}
int main()
{
	freopen("48.in","r",stdin);
	//freopen("48.out","w",stdout);
	scanf("%d%d",&N,&R);
	for(int i=1;i<=N;i++)
	scanf("%d",&A[i]);
	for(int i=1;i<=N;i++)
	{
		int aa=A[i]-R,bb=A[i]+R;
		aa=max(aa,0); //注意取值範圍
		bb=min(bb,10000);  
		c[i].a=aa;
		c[i].b=bb;
	}
	sort(c+1,c+1+N,cmp);  //按每條線段的左端點由小到大排序
	solve();
	return 0;
}


發佈了57 篇原創文章 · 獲贊 8 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章