【问题描述】 (注意:本题的距离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
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;
}
考后反思:看数据范围是一定要仔细,这次失分就是因为没有注意村庄的纵坐标可以为负。