jzoj 3833. 平坦的折線(lam)

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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章