문제 후기
어렵다.. 발상을 요하는 것 같다.
문제 설명
레스토랑 외벽 중 취약 지점 몇 군데를, 몇 명이서 정해진 시간 내에 점검해야한다.
- 동그란 모양이다.
- 총 둘레 n 미터.
- 사람 별로 이동 가능한 거리가 다름.
- 최소한의 사람 수 구하기.
입력 예시
1. 외벽 둘레인 n = 12
2. 취약 지점 위치 배열인 weak = [1,5,6,10].
3. 사람별로 이동 가능한 거리 배열인 dist = [1,2,3,4].
출력 예시
1. 최소 사람 수인 2
- 모든 경우의 수
- 한가지 경우의 수 동작 예시.사람을 ㄱ→ㄴ→ㄷ→ㄹ 순으로 배치.
- a 취약 지점에 ㄱ을 배치.
- 한시간 뒤에 ㄱ이 b까지 점검할 수 있는지 확인
- 된다면, b까지 점검할 수 있는지 확인
- 된다면, c까지 점검할 수 있는지 확인
- 안된다면, 다음 사람 ㄴ이 b를 맡음
- ㄴ이 다음 취약 지점 c를 점검할 수 있는지 확인
- 된다면, d까지 점검할 수 있는지 확인
- 안된다면, 다음 사람 ㄷ이 d를 맡음
- ㄴ이 다음 취약 지점 c를 점검할 수 있는지 확인
- 된다면, b까지 점검할 수 있는지 확인
- 취약 지점 a→b→c→d 순으로 사람 배치.
- 한가지 경우의 수 동작 예시.사람을 ㄱ→ㄴ→ㄷ→ㄹ 순으로 배치.
- 취약 지점 순서의 경우의 수 ⇒ start=0, start=1, start=2… 로 하여 경우 나누기
package week2.p60062;
import java.util.*;
public class Solution {
public int solution(int n, int[] weak, int[] dist) {
// 취약 지점을 계산하기 쉽게 선형으로 바꿈
int len = weak.length;
// 선형 취약지점//출발지점으로부터 거리 계산이 쉬워짐. 사람 수
int[] extendedWeak = new int[len * 2];
for (int i = 0; i < len; i++) {
extendedWeak[i] = weak[i];
extendedWeak[i + len] = weak[i] + n;
}
// 친구 순열을 계산
Arrays.sort(dist); // 친구들의 이동 거리를 오름차순으로 정렬
int answer = dist.length + 1; // 친구들을 모두 투입해도 안 되는 경우 대비 (최댓값)
for (int start = 0; start < len; start++) {
//1등 친구를 어느 지점부터 투입 시킬지에 따라, 최소 인원수가 달라질 수 있다.
do {
answer = Math.min(answer, findMinimumFriends(start, len, extendedWeak, dist));
} while (nextPermutation(dist)); // 친구들의 순열을 모두 탐색
}
// 모든 취약 지점을 덮을 수 없으면 -1 반환
return answer > dist.length ? -1 : answer;
}
// 주어진 친구 순서에서 최소 몇 명의 친구가 필요한지 계산
private int findMinimumFriends(int start, int len, int[] extendedWeak, int[] dist) {
//start: 어떤 취약 지점을 점검하는 것으로 시작할 것인지, 취약 지점 총 개수
//len: 취약 지점이 몇 개인지
int count = 1; // 첫번째 친구
int position = extendedWeak[start] + dist[dist.length - count]; // 첫 번째 친구가 덮을 수 있는 최대 거리
//남은 취약 지점의 개수를 다 점검할 때 까지 반복
for (int i = start + 1; i < start + len; i++) {
//start+1(시작 다음지점)부터 시작해서 start+len까지 취약 지점들을 점검
//len
if (position < extendedWeak[i]) { //시작 다음지점을 지금 친구가 못 덮을 경우
count++; //두번째 친구한테로.
if (count > dist.length) { //모든 친구를 다 쓴 경우.
return dist.length + 1; //이렇게 해서 나중에 -1 반환하도록.
}
position = extendedWeak[i] + dist[dist.length - count]; //두번째 친구가 덮을 수 있는 최대 거리
//5 ---- 9 - 10 ----- 13(1)
}
}
return count;
}
// 다음 순열을 생성하는 메소드 (사전순으로 다음 순열을 생성)
private boolean nextPermutation(int[] dist) {
int i = dist.length - 1;
while (i > 0 && dist[i - 1] >= dist[i]) {
i--;
}
if (i == 0) {
return false; // 더 이상 다음 순열이 없음
}
int j = dist.length - 1;
while (dist[i - 1] >= dist[j]) {
j--;
}
swap(dist, i - 1, j);
int k = dist.length - 1;
while (i < k) {
swap(dist, i++, k--);
}
return true;
}
private void swap(int[] dist, int i, int j) {
int temp = dist[i];
dist[i] = dist[j];
dist[j] = temp;
}
public static void main(String[] args) {
Solution solution = new Solution();
int n = 12;
int[] weak = {1, 5, 6, 10};
int[] dist = {1, 2, 3, 4};
System.out.println(solution.solution(n, weak, dist)); // 예시 출력: 2
}
}