문제 분석
https://www.acmicpc.net/problem/1027
N개의 원소가 주어진다.
각 원소는 빌딩의 높이를 의미한다.
i번째 빌딩에서 j번째 빌딩이 보인다는 뜻은 두 빌딩의 꼭대기를 포함하는 직선에 그 사이의 다른 빌딩이 접하거나 만나지 않아야 한다는 것이다.
이때, 가장 많은 빌딩이 보이는 빌딩에서 볼 수 있는 빌딩의 수를 구해야 한다.
처음에는, 전체 배열 중 가장 높이가 높은 값을 기준으로 LIS를 왼쪽에서 TOP 오른쪽에서 TOP해서 두번 구하는 방식으로 풀어보려 했으나..
문제의 조건이 단순히 높이가 낮으면 보이는 것이 아닌 두 빌딩을 이은 선분에 맞닿는 빌딩이 없어야 보인다는 것이었기에 LIS로는 해당 조건을 만족시키기 꽤 어려웠다.
근데, N 자체가 50밖에 되지 않는다.
즉, n^3의 풀이가 125000 번의 반복으로 들어가기에 시간 초과가 발생하지 않게 된다.
그래서 아주 단순하게
0번 부터 쭉 순서대로 진행하며 각 i번째 빌딩에 대해서
i-1 ~ 0번째 빌딩 그리고 i+1 ~ n-1번째 빌딩을 순차적으로 보이는 지 여부를 검사하면 된다.
즉 해당 검사 대상 빌딩을 j번째 빌딩이라 할 때, i~j빌딩을 잇는 선분의 기울기를 구하고
i~j 사이의 빌딩 k에 대해 해당 선분의 아래에 있는 지 확인해주면 된다.
주의할 점은, i~j사이의 최댓값을 저장하고 이를 넘지 않는 지만 체크하면 답을 구할 수 없게 된다.
5,5, 6,3 .... 50,2 ... 55,1 대충 이런 구성으로 되어있는 경우를 생각해보자
(5,5 과 55,1을 잇는 선분에 대해 3이 max라고 할 때 3은 선분 아래에 있지만 50,2는 선분 위에 있다)
코드
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
int ans = 0;
for (int i = 0; i < n; i++) {
int nowCount = 0;
for (int j = i-1; j >= 0; j--) {
//left to Target
// 11 22
double gradient = (double)(arr[j] - arr[i])/(j-i);
boolean isPossible = true;
for (int k = i-1; k > j; k--) {
double maxHeight = gradient*(k-i) + arr[i];
if(maxHeight <= arr[k]){
isPossible=false;
break;
}
}
if(isPossible)
nowCount++;
}
//right to Target
for (int j = i+1; j < n; j++) {
double gradient = (double)(arr[j] - arr[i])/(j-i);
boolean isPossible = true;
for (int k = i+1; k < j; k++) {
double maxHeight = gradient*(k-i) + arr[i];
if(maxHeight <= arr[k]){
isPossible=false;
break;
}
}
if(isPossible)
nowCount++;
}
ans = Math.max(ans, nowCount);
}
System.out.println(ans);
}
}
'Algorithm > Acmicpc' 카테고리의 다른 글
22866 탑보기 [JAVA] (0) | 2024.10.25 |
---|---|
4179 불! [JAVA] (0) | 2024.10.18 |
2138 전구와 스위치 [JAVA] (0) | 2024.10.16 |
1253 좋다 [JAVA] (1) | 2024.10.15 |
4485 녹색 옷 입은 애가 젤다지? [JAVA] (0) | 2024.10.15 |