Description
現在我們在一張紙上有一個笛卡爾座標系。我們考慮在這張紙上用鉛筆從左到右畫的折線。我們要求任何兩個點之間連接的直線段與x軸的夾角在-45~45之間,一條滿足以上條件的折線稱之爲平坦的折線。假定給出了n個不同的整點(座標爲整數的點),最少用幾條平坦的折線可以覆蓋所有的點?
例子:
圖中有6個整點:(1,6), (10,8), (1,5), (2,20), (4,4), (6,2),要覆蓋它們至少要3條平坦的折線。
任務:
寫一個程序:
從文件lam.in中讀入點的個數以及它們的座標。
計算最少需要的折線個數。
將結果寫入文件lam.out。
Input
在輸入文件lam.in的第一行有一個正整數n,不超過30000,代表點的個數。接下來的n行表示這些點的座標,每行有兩個用一個空格隔開的整數x,y,0 <= x <= 30000, 0 <= y <= 30000。第i+1行的數字代表第i個點的座標。
Output
在輸出文件lam.out的第一行應當有且僅有一個整數——表示覆蓋所有的點最少需要的折線數。
Sample Input
6
1 6
10 8
1 5
2 20
4 4
6 2
Sample Output
3
Data Constraint
數據規模
對於20%的數據,有N<=15。
對於100%的數據如題目。
題目大意:
求最少要幾個與x軸的夾角在-45~45度的折線,覆蓋所有的點。
題解:
與x軸的夾角在-45~45度這個條件很難處理,考慮將其逆時針轉45度,x’=x-y,y’=x+y
原來:
轉化成:
這樣條件變成只要使線段不下降(斜率大於0)就行了,
將新的座標按x爲第一關鍵字,y爲第二從小到大排序,
條件又變成只用使y座標不下降
問題就變成同導彈攔截(NOIP1999)一樣,求用多少個不下降序列覆蓋完所有點
答案即爲最長下降序列的長度(因爲最長下降序列的每個點都可以做一個不下降序列的起點)
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 30005
#define Max 9999999997
using namespace std;
int i,j,n,m,num,x,y;
int f[N];
struct P {
int x,y;
}p[N];
bool cmp(P a,P b) {
return (a.x<b.x)||(a.x==b.x&&a.y<b.y);
}
int find(int tar)
{
int l=1,r=num,mid,ans;
while (l<=r) {
mid=(l+r)/2;
if (f[mid]==tar) return 0;
if (f[mid]>tar) l=mid+1;
if (f[mid]<tar) r=mid-1;
}
return l;
}
int main()
{
freopen("lam.in","r",stdin);
freopen("lam.out","w",stdout);
scanf("%d",&n);
for (i=1;i<=n;i++) {
scanf("%d%d",&x,&y);
p[i].x=x-y; p[i].y=x+y;
}
sort(p+1,p+1+n,cmp);
for (i=0;i<=n;i++) f[i]=Max;
for (i=1;i<=n;i++) {
if (p[i].y<f[num]) f[++num]=p[i].y;
else {
x=find(p[i].y);
f[x]=p[i].y;
}
}
printf("%d",num);
}