[Algorithm Problem] 고층 빌딩 (BAEKJOON: 1027)
고층 빌딩 (BAEKJOON: 1027)
이번 문제는 임의의 점 P(x, y) (단, 1 <= x <= 50, 1 <= y <= 10^9)가 평면 위에 최대 50개까지 주어질 때, 임의로 이은 두 점이 x축과 직교하는 선에 닿지 않는 개수를 모두 세고, 그 중 최대 개수를 구함으로써 풀 수 있다. 이는 기준 지점에서 가까운 방향부터 먼 방향으로 레이저 스캔을 진행할 때, 뒤에 가려진 부분은 제외하고 꼭지점 부분만 세는 방법을 물어보는 것과 같다.
여기서 핵심은 직교하는 선에 닿는가를 판단하는 방법이다. 이를 조금 더 단순화 해보자. 임의의 두 점 $P(x_1, y_1), Q(x_2, y_2)$가 있다고 가정하자. 이 때, $x_1 < x_2$ 이며 $y_1 < y_2$ 이다. 즉, $\overrightarrow {PQ}$ 기울기는 0보다 크다.
이 때, $x_1 < x_3 < x_2$인 위치에 점 $R(x_3, y_3)$이 주어졌다고 가정하자. 이 때, x축과 점 R을 이은 선분과 PQ가 만드는 직선이 만나지 않을 조건은 무엇일까? 간단하다. 점 R은 직선 PQ 아래 위치해야 한다. 즉, $\overrightarrow {PR}$이 이루는 기울기가 $\overrightarrow {PQ}$이 이루는 기울기보다 작으면 된다.
이 굉장히 직관적이고 단순한 판단 방법을 구현하는 방법이 조금 까다로운 문제였다. 바깥쪽에서부터 검사하는 방법도 가능하고, 기준 점에서 멀어지는 방향으로 검사하는 방법도 가능하다. 여러 방법으로 풀 수 있으며, 50개가 최대이기 때문에 아마 대부분 제한 시간 안에 통과될 것이라 생각한다.
풀이1: 좌측, 우측을 나누어 판단
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long int lli;
lli arr[60];
int N;
int watchable(lli _arr[], int curIdx) {
int ans;
long double criteriaGradient;
long double gradient;
ans = 0; criteriaGradient = 12345678910;
// Left side
for (int i = curIdx - 1; 0 < i; i--) {
gradient = (double)(arr[curIdx] - arr[i]) / (curIdx - i);
if (gradient < criteriaGradient) {
ans += 1;
criteriaGradient = gradient;
}
}
criteriaGradient = -12345678910;
// Right side
for (int i = curIdx + 1; i <= N; ++i) {
gradient = (double)(arr[curIdx] - arr[i]) / (curIdx - i);
if (criteriaGradient < gradient) {
ans += 1;
criteriaGradient = gradient;
}
}
return ans;
}
int main(int argc, char* argv[]) {
ios_base::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
cin >> N;
for (int i = 1; i <= N; i++) {
cin >> arr[i];
}
int ans = 0;
for (int i = 1; i <= N; i++) {
ans = max(ans, watchable(arr, i));
}
cout << ans;
return 0;
}
풀이2: 오른쪽으로 검사하며 점 개수 파악
#include<iostream>
#define MIN_GRADIENT -9999999999
using namespace std;
typedef long long int lli;
lli arr[60];
int cnt[60];
int main(int argc, char* argv[]) {
ios_base::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
int N;
cin >> N;
for (int i = 0; i < N; i++) cin >> arr[i];
double maxGradient, gradient;
for (int i = 0; i < N - 1; i++) {
maxGradient = MIN_GRADIENT; // init
for (int j = i + 1; j < N; j++) {
gradient = (double)(arr[i] - arr[j]) / (i - j);
if (maxGradient < gradient) {
cnt[i] += 1;
cnt[j] += 1;
maxGradient = gradient;
}
}
}
int maxVal = 0;
for (int i = 0; i < N; i++) maxVal = maxVal < cnt[i] ? cnt[i] : maxVal;
cout << maxVal;
return 0;
}
Leave a comment