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

Cpp环境【Uva1615】【Vijos2867】 freeway 高速公路

2016-07-27 09:47 204 查看
【问题描述】


  BOB是一名优秀的工程设计师,他正在设计一条穿越的农村地区的高速公路。为了方便一些村庄的人安全而快捷穿越高速路,需要设计跨越高速公路的人行天桥。当然为了节约成本,BOB须尽量减少天桥的数量。

  在BOB的设计图纸上,高速公路是一条长为L的线段,它的左端点是平面坐标系的原点,右端点是x轴正方向的某个点。所有村庄在坐标系中标记成点。

  现在请你帮助BOB确定需要修建人行天桥的最少数量,满足每个村庄与最近的天桥的曼哈顿距离不超过D。

【输入格式】


  第1行是一个整数L(1<=L<=10^9),表示高速公路的长度。

  第2行是一个整数D(1<=D<=10^9),表示村庄离自己最近的天桥的不超过D。

  第3行是一个整数n(n<=10^5),表示村庄数目。

  接下来的n行,每行包含两个整数x,y,表示村庄的位置坐标(0<=x<=L,y的绝对值小于D)。

【输出格式】


  一个整数,表示修建人行天桥的最小数量。

【输入样例】


15

5

5

0 1

2 4

6 3

8 2

13 2

【输出样例】


3

【数据范围】


30%的数据满足:n<=10

70%的数据满足:n<=10,000

100%的数据满足:n<=100,000

【思路梳理】


  稍微变通一下就能够发现这是非常简单的一道区间选点问题。显然先考虑设置天桥再依次计算天桥与每个村庄的距离不太现实(坐标轴上每一个点都必须考虑到),那么我们可以考虑从村庄入手。

  显然每个村庄有一个设置天桥的范围——天桥一旦处于这个范围以外,到村庄的曼哈顿距离就会超过d。首先考虑如何来求出这个范围。因为高速公路与x轴重合,那么我们可以得到:村庄到高速公路(x轴)的距离=y。天桥一定是在x轴上,也就是说我们将这个村庄“拉”到了高速公路上,此时天桥与村庄的距离就不能够超过d-y。我们成功地将点变成了区间:对于第i个村庄a[i],设置可以满足它需求的天桥的区间是:[x-(d-y),x+(d-y]。

  接着就变成了区间选点的问题,区间有大有小,我们需要贪心地确定最小数量的点使得每一个区间都包含至少一个点。只需要按照右端点从小到大排序即可。

  贪心策略:第1个区间interval的点须放在第一个区间的最右端interval[1].end,然后凡是包含这个点的区间,都pass掉,当遇到第一个不包含interval[1].end的区间i,则又需要选择这个区间的右端点interval[i].end,然后再继续,这样选择出来的点数量一定是最小的。

【Cpp代码】


#include<cstdio>
#include<algorithm>
#include<cmath>
#define maxn 100005
using namespace std;
int L,D,n;
struct info
{
int start,end;
}interval[maxn];//区间的英文名称

bool cmp(info a,info b)
{
return a.end<b.end;
}

void TASK()
{
int ans=1;int pos=interval[1].end;
for(int i=1;i<=n;i++)
if(pos>=interval[i].start) continue;
else    ans++,pos=interval[i].end;
printf("%d",ans);
}

int main()
{
//freopen("in.txt","r",stdin);
scanf("%d%d%d",&L,&D,&n);
for(int i=1;i<=n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
interval[i].start=x-(D-abs(y));//注意y值有正有负,要取一个绝对值
interval[i].end=x+(D-abs(y));
}
sort(interval+1,interval+1+n,cmp);//按照右端点由小到大排序
TASK();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息