您的位置:首页 > 编程语言 > C语言/C++

2014NOIP复赛模拟练习 设置喷水池 解题报告

2016-07-21 14:15 232 查看
【问题描述】

  笑笑家的楼下是一条绿化带,可以用一条从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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ 复赛模拟