2421. Mountain View
題目描述
從農場裏奶牛Bessie的牧草地向遠端眺望,可以看到巍峨壯麗的山脈綿延在地平線上。山脈裏由N座山峯(1≤N≤10^5)。如果我們把Bessie的視野想象成xy平面,那麼每座山峯都是一個底邊在x軸上的三角形。山峯的兩腰均與底邊成45度角,所以山峯的峯頂是一個直角。於是山峯i可以由它的峯頂座標(xi,yi)精確描述。沒有兩座山峯有完全相同的峯頂座標。
Bessie嘗試數清所有的山峯,然而由於它們幾乎是相同的顏色,所以如果一座山峯的峯頂在另一座山峯的三角形區域的邊界上或是內部,她就無法看清。
請求出Bessie能夠看見的不同的山峯的峯頂的數量,也就是山峯的數量。
輸入
輸入的第一行包含N。以下N行每行包含xi(0≤xi≤109)和yi(1≤yi≤109),描述一座山峯的峯頂的座標。
輸出
輸出Bessie能夠分辨出的山峯的數量。
樣例輸入
3
4 6
7 2
2 5
樣例輸出
2
提示
在這個例子中,Bessie能夠看見第一座和最後一座山峯。第二座山峯被第一座山峯掩蓋了。
思路:
首先來複習一下小學的數學知識,一個直角等腰三角形的高(過直角頂點的那條)=底(直角相對的那條底)/2。接着來做就簡單了。
根據題意一座山如果不被擋住(拍照時,你的頭不想被其他頭擋住,你就別站比你高的人後面),那這座山一定是比較高,或者雖然矮,但沒有在其他山的裏面。於是思路就出來了。
我們先按照山的高矮做降序排序(從高到低)。一開始要假設所以山都能看見,再模擬每座山能擋住的山,將它們減掉。這樣做會超時,最壞情況O(n^2),但我們可以優化一下,只有沒被擋住的山才能去擋更矮的山。數據比較水,God bless me!
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
using namespace std;
const int MAX=2147483647;
const int N=1e5+10;
struct node
{
int d,h;
} s[N];
int n,ans;
bool vis[N];
bool cmp(node x,node y) {return x.h>y.h;}
void input()
{
scanf("%d",&n);
ans=n;
for(int i=1;i<=n;i++) scanf("%d%d",&s[i].d,&s[i].h);
sort(s+1,s+1+n,cmp);
}
int main()
{
fre(mountains);
input();
for(int i=1;i<n;i++)
{
if(!vis[i]) //小小優化
{
int l=s[i].d-s[i].h,r=s[i].d+s[i].h;
for(int j=i+1;j<=n;j++)
{
int ll=s[j].d-s[j].h,rr=s[j].d+s[j].h;
if(l<=ll&&r>=rr&&!vis[j]) vis[j]=1,ans--;
}
}
}
printf("%d\n",ans);
return 0;
}
當然,大佬yty想到了O(n)的方法:
#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
struct hhx{
long long x,y;
}a[100010];
long long n,ans,x,y;
bool cmp(hhx t,hhx x)
{
if (t.x==x.x)
return (t.y>x.y);
else return (t.x<x.x);
}
int main()
{
freopen("mountains.in","r",stdin);
freopen("mountains.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
a[i].x=x-y;
a[i].y=x+y;
}
sort(a+1,a+n+1,cmp);
x=0;
for (int i=1;i<=n;i++)
{
if (a[i].y>x)
{
x=a[i].y;
ans++;
}
}
cout<<ans<<endl;
fclose(stdin);
fclose(stdout);
return 0;
}