【問題描述】
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;
}