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

UVA1615 高速公路(highway)(重庆一中高2018级信息学竞赛测验5) 解题报告

2016-07-28 08:30 267 查看
【问题描述】 (注意:本题的距离D指的是每个村庄与最近的天桥的曼哈顿距离不超过D,而原题的距离D指的是每个村庄与最近的天桥的欧几里得距离不超过D)

  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,-D<y<D 且y!=0)。

【输出格式】

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

【输入样例】

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

【来源】

《算法竞赛》255页 uva 1615

做题思路(正解):根据题意,因为高速公路在x轴上,我们可以先计算出每个村庄可以到x轴(高速公路)上的位置的最小值和最大值,将它们看作一个区间,则该题就被转化为区间选点问题(即给你n个区间,选择尽量少的点,使得每个区间里至少有一个选择的点)。解决该类问题的核心思路为贪心,贪心策略为每次选择当前区间的最右端,这样才能既使得该区间里有一个点被选择,又使得可以该点在更多的区间里。所以,在实现贪心算法时,先按区间的右端点由小到大排序,每选择一个区间的右端点,就将包含该点的区间跳过,然后重复上述步骤。需要注意的是,村庄的纵坐标可能为负,在计算村庄到x轴的位置的最小值和最大值时,要取纵坐标的绝对值,我考试时就是错在了这里。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=100005;
int L,D,N;
struct data
{
int x,y,a,b;
};
data c[maxn];
bool cmp(data aa,data bb)
{
return aa.b<bb.b;
}
void solve()  //区间选点问题
{
sort(c+1,c+1+N,cmp);  //按区间的右端点由小到大排序
int i=1,cnt=0;
while(i<=N)
{
int now=c[i].b;
cnt++;
i++;
while(i<=N && c[i].a<=now)  i++;  //将包含该点的区间跳过(因为这些区间里已经有一个选择的点了)
}
printf("%d\n",cnt);
}
int main()
{
//freopen("freeway.in","r",stdin);
//freopen("freeway.out","w",stdout);
scanf("%d%d%d",&L,&D,&N);
for(int i=1;i<=N;i++)
scanf("%d%d",&c[i].x,&c[i].y);
for(int i=1;i<=N;i++)  //计算每个村庄可以到x轴(高速公路)上的位置的最小值和最大值
{
c[i].a=c[i].x-(D-abs(c[i].y));
c[i].b=c[i].x+(D-abs(c[i].y));
}
solve();
return 0;
}

考后反思:看数据范围是一定要仔细,这次失分就是因为没有注意村庄的纵坐标可以为负。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ uva