console.log
[SWEA] 2383 점심 식사시간 JAVA 본문
https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5-BEE6AK0DFAVl
SW Expert Academy
SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!
swexpertacademy.com
메모리 : 28,940 kb
실행시간 : 138 ms
문제분석
[부분집합 + 빡구현]
1. 입력 받으면서 사람, 계단 위치 저장
2. 맨헤튼 거리로 계단까지 이동, 계단 내려가는 시간
[계단]
1. 계단 입구까지 이동, 다음 턴에 계단 내려가기
2. 동시에 3명 가능
3. K분 동안 내려가기
사람 1 - 10명
계단은 무조건 2개
걸린시간
2시간 ⏱️
풀이방법
풀이 방법
1. 조합으로 팀 가르기 (0 - 전체)
2. 계단까지의 시간 계산해서 저장
3. 시간별로 시뮬레이션 실행
4. 최저값 저장 후, 초과 시 더이상 계산하지 않음
시뮬레이션 (모든 사람이 이동 완료할 때까지 1분씩 추가하며 실행)
[사람]
1. 계단까지의 거리 체크 후 계단 대기열에 추가
2. 계단까지의 거리 체크 후 계단으로 1칸 이동
[계단]
1. 계단 위에 있는 사람 한 칸씩 내려가기
- 0이 된 사람은 리스트에서 삭제
2. 대기열에 사람이 있고 계단에 사람을 추가할 수 있을 때
- 대기열에서 삭제
- 사람 수 추가
- 배열에 사람 번호와 남은 시간 추가
포인트
객체를 잘 구현해서 시간 별로 시뮬레이션 돌려야 한다 !!!
부분집합을 활용해 2가지 계단을 어떤 사람들이 이용할 지 모든 경우를 확인해야 한다 !!
코드
import java.io.*;
import java.util.*;
public class Solution {
public static int answer, N, group;
public static int[][] map;
public static Stair[] stairs;
public static Person[] person;
public static boolean[] num, check;
// 계단 객체
public static class Stair {
public int x; // x좌표
public int y; // y좌표
public Queue<int[]> list; // 해당 계단에 위치한 사람 번호와 남은 시간
public Queue<Integer> q; // 계단 대기열
public int time; // 길이
public Stair(int x, int y, int time) { // 생성자
this.x = x;
this.y = y;
this.list = new ArrayDeque<>();
this.q = new ArrayDeque<>();
this.time = time;
}
public boolean inPeople(int num) { // 계단 초과 여부 반환
if(this.list.size() < 3) return true;
else return false;
}
public void reset() {
this.list = new ArrayDeque<>();
this.q = new ArrayDeque<>();
}
}
public static class Person {
public int x; // x좌표
public int y; // y좌표
public int time; // 계단까지의 이동 시간
public int stairNum; // 계단 넘버
public String state; // 해당 사람의 상태 (계단 도착 전 : "N", 계단 대기 : "W")
public Person(int x, int y) { // 생성자
this.x = x;
this.y = y;
this.time = 0;
this.stairNum = -1;
this.state = "N";
}
public void setState(String state) { // 상태 변경
this.state = state;
}
public void reset() { // 초기화
this.time = 0;
this.stairNum = -1;
this.state = "N";
}
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
StringBuilder sb = new StringBuilder();
int T = Integer.parseInt(br.readLine());
for(int t = 1; t <= T; t ++) {
answer = Integer.MAX_VALUE; // 결과값 초기화
N = Integer.parseInt(br.readLine()); // 방 크기 설정
map = new int[N][N]; // 방 생성
stairs = new Stair[2]; // 계단 객체 저장 배열
int countPeople = 0; // 전체 인원 수 체크
int idx = 0; // 인덱스
// 방 저장
for(int i = 0; i < N; i ++) {
st = new StringTokenizer(br.readLine());
for(int j = 0; j < N; j ++) {
map[i][j] = Integer.parseInt(st.nextToken());
if(map[i][j] == 1) { // 인원 수 체크
countPeople ++;
}
if(map[i][j] > 1) { // 계단 객체 생성 후 저장
stairs[idx ++] = new Stair(i, j, map[i][j]);
}
}
}
// 사람 저장
person = new Person[countPeople];
idx = 0;
for(int i = 0; i < N; i ++) {
for(int j = 0; j < N; j ++) {
if(map[i][j] == 1) {
person[idx ++] = new Person(i, j);
}
}
}
// 사람 별로 어떤 계단을 이용할 지 부분집합으로 결정
for(int i = 0; i <= countPeople; i ++) {
num = new boolean[countPeople]; // 체크 배열 초기화
group = i; // 최대 인원
subset(0, 0); // 부분집합 구하기
}
sb.append("#" + t + " " + answer + "\n");
}
System.out.println(sb);
}
// 부분 집합으로 어떤 계단 이용할 지 구분하기
public static void subset(int r, int start) {
// 재귀 종료 조건
if(r == group) {
// 시간 별 이동 체크하기
movecheck();
reset();
return;
}
// 인덱스 벗어날 경우 돌아가기
if(start == num.length) return;
num[start] = true;
subset(r + 1, start + 1);
num[start] = false;
subset(r, start + 1);
}
// 시간 별로 이동 체크하기
public static void movecheck() {
// 정해진 계단과의 거리 계산하기
for(int i = 0; i < person.length; i ++) {
if(num[i]) { // 부분집합 결과에 따라 해당 계단과의 거리 계단
person[i].stairNum = 1;
person[i].time = Math.abs(stairs[1].x - person[i].x) + Math.abs(stairs[1].y - person[i].y);
} else {
person[i].stairNum = 0;
person[i].time = Math.abs(stairs[0].x - person[i].x) + Math.abs(stairs[0].y - person[i].y);
}
}
// 시간 별로 사람 이동시키기
int minute = 0;
check = new boolean[person.length];
outer : while(true) {
// 최소 시간을 이미 넘긴 경우 리턴
if(minute >= answer) return;
minute ++; // 1분 지남
// 모든 사람 이동
for(int i = 0; i < person.length; i ++) {
if(person[i].time == 0) { // 계단까지의 거리가 0인 경우
if(person[i].state == "N") { // 계단 도착 전인 상태인 경우
stairs[person[i].stairNum].q.add(i); // 해당 계단 대기열에 추가
person[i].setState("W");
}
} else { // 계단까지의 거리가 1이상인 경우
person[i].time --; // 한 칸 이동
}
}
// 계단 위에 있는 사람 이동
for(int i = 0; i < 2; i ++) {
int size = stairs[i].list.size(); // 현재 해당 계단 위에 위치한 사람 수
for(int j = 0; j < size; j ++) { // 계단 위에 있는 사람 이동하기
int[] temp = stairs[i].list.poll();
if(temp[1] > 1) { // 이동 후에도 도착하지 않는 사람만 다시 큐에 삽입
stairs[i].list.offer(new int[] {temp[0], temp[1] - 1});
} else { // 계단을 모두 내려온 사람
check[temp[0]] = true; // 이동 완료 체크
}
}
}
// 계단 대기열에 있는 사람 이동
for(int i = 0; i < 2; i ++) {
int cnt = 3 - stairs[i].list.size(); // 추가 가능한 인원 수
while(cnt > 0) {
// 대기 인원 이동 시작
if(stairs[i].q.size() > 0) {
stairs[i].list.add(new int[] {stairs[i].q.poll(), stairs[i].time});
} else break;
cnt --;
}
}
// 모든 사람이 계단을 내려왔는지 체크
boolean flag = true;
for(int i = 0; i < person.length; i ++) {
if(!check[i]) {
flag = false;
continue;
}
}
if(flag) break outer; // 모든 사람이 내려온 경우 반복문 종료
}
// 최소 시간 저장 후 리턴
answer = Math.min(answer, minute);
return;
}
// 모든 객체 상태 초기화
public static void reset() {
for(int i = 0; i < person.length; i ++) {
person[i].reset();
}
for(int i = 0; i < 2; i ++) {
stairs[i].reset();
}
}
}
'알고리즘 > SW Expert Academy' 카테고리의 다른 글
[SWEA] 1949 등산로 조성 JAVA (1) | 2023.10.21 |
---|---|
[SWEA] 2382 미생물 격리 JAVA (1) | 2023.10.20 |
[SWEA] 2477 차량 정비소 JAVA (0) | 2023.10.18 |
[SWEA] 4014 활주로 건설 JAVA (0) | 2023.10.17 |
[SWEA] 2105 디저트 카페 JAVA (1) | 2023.10.16 |