백준 2564 - 경비원
Updated:
Java
2564 번 - 경비원
문제
블록의 크기와 상점의 개수 및 위치 그리고 동근이의 위치가 주어질 때 동근이의 위치와 각 상점 사이의 최단 거리의 합을 구하는 프로그램을 작성하시오.
접근 방법
처음에는 문제에서 제시한 대로 동근이의 처음 위치에서 시계방향으로 탐색하여 상점들을 찾는다.
찾은 상점까지의 거리와 직사각형 둘레의 길이를 뺀 값 중, 짧은 값을 상점까지 최소 거리로 하여 정답을 구하였다.
두번째로는 동원이와 상점의 위치를 파악하여, 각 경우의 수대로 조건문을 통해 거리를 구하였다.
동원과 상점의 위치가, 수직으로 위치하면 ex) (1 , 3) or (2 , 3)
두 x와 y의 차이가 최단 거리이고
수평으로 위치하면 ex) (1,2) or (3,4) or (1,1)
[현재 위치의 수직의 값 + 각 점까지의 거리의 차이(같은 라인일 때) or 합(다른 라인일 때)]이 최단거리가 된다.
코드
import java.util.*;
import java.io.*;
public class Main {
static int n, m, result;
static int dir, diff, y, x;
public static void main(String []args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stk = new StringTokenizer(br.readLine());
m = stoi(stk.nextToken());
n = stoi(stk.nextToken());
int k = stoi(br.readLine());
ArrayList<int[]> loc = new ArrayList<>();
for(int i = 0; i < k; i++) {
stk = new StringTokenizer(br.readLine());
loc.add(new int[] {stoi(stk.nextToken()), stoi(stk.nextToken())} );
}
stk = new StringTokenizer(br.readLine());
dir = stoi(stk.nextToken()); // 동근이의 방향
diff = stoi(stk.nextToken());
int[] location = point(dir,diff);
y = location[0]; // 동근이의 처음 위치
x = location[1];
// 각 상점의 값을 주어, 최단 거리를 구한다.
for(int[] arr : loc) {
result += rollin(arr);
}
System.out.println(result);
br.close();
}
// 시계 방향 회전
static int[] dy = {-1,0,1,0};
static int[] dx = {0,1,0,-1};
// 왼쪽부터, 하, 우, 좌, 상
private static int rollin(int[] arr) {
int count = 0;
int loopIdx = 0;
// 현재 동근이의 위치에 따라 처음 도는 방향이 정해진다
if(dir == 1)
loopIdx = 1;
else if(dir == 2)
loopIdx = 3;
else if(dir == 3)
loopIdx = 0;
else if(dir == 4)
loopIdx = 2;
int curY = y;
int curX = x;
// 목표 상점의 위치
int[] temp = point(arr[0], arr[1]);
int targetY = temp[0];
int targetX = temp[1];
// 시계 방향으로 목표 상점을 만날 때 까지 탐색을 시작한다.
while(true) {
count++;
curY += dy[loopIdx];
curX += dx[loopIdx];
// 직선으로 가다가 맵 밖으로 나가면, 방향을 바꾸어 시계 방향으로 돈다.
if(!isIn(curY, curX)) {
curY -= dy[loopIdx];
curX -= dx[loopIdx];
loopIdx = (loopIdx + 1) % 4;
curY += dy[loopIdx];
curX += dx[loopIdx];
}
if(curY == targetY && curX == targetX)
break;
}
count = Math.min(count, 2 * n + 2 * m - count);
return count;
}
// 주어진 범위 안에 있는가
public static boolean isIn(int y, int x){
if(y < 0 || y > n || x < 0 || x > m)
return false;
return true;
}
// 방향과 떨어진 거리를 입력 받아, 좌표를 반환한다.
private static int[] point(int a, int b) {
switch(a) {
case 1:
return new int[] {0, b};
case 2:
return new int[] {n, b};
case 3:
return new int[] {b, 0};
case 4:
return new int[] {b, m};
}
return null;
}
static int stoi(String str) {
return Integer.parseInt(str);
}
}
코드 - 2
import java.util.*;
import java.io.*;
public class Main {
static int n, m, result;
static int dir, diff, y, x;
public static void main(String []args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer stk = new StringTokenizer(br.readLine());
m = stoi(stk.nextToken());
n = stoi(stk.nextToken());
int k = stoi(br.readLine());
ArrayList<int[]> loc = new ArrayList<>();
for(int i = 0; i < k; i++) {
stk = new StringTokenizer(br.readLine());
loc.add(new int[] {stoi(stk.nextToken()), stoi(stk.nextToken())} );
}
stk = new StringTokenizer(br.readLine());
dir = stoi(stk.nextToken()); // 동근이의 방향
diff = stoi(stk.nextToken());
int[] location = point(dir,diff);
y = location[0]; // 동근이의 처음 위치
x = location[1];
int sy, sx, sdir;
for(int[] arr : loc) {
sdir = arr[0];
location = point(sdir, arr[1]);
sy = location[0];
sx = location[1];
int min = 0;
// 수직으로 위치하여 있으면
if((dir <= 2 && sdir >= 3) || (dir >= 3 && sdir <= 2)) {
result += Math.abs(y - sy) + Math.abs(x - sx);
}
// 수평으로 위치하여 있으면
else if(dir <= 2 && sdir <= 2){
if(dir != sdir) // 같은 라인에 있지 않으면
min = sx + x;
else
min = Math.abs(sx - x);
result += Math.abs(sy - y) + Math.min(min, 2 * m - min);
}
else if(dir >= 3 && sdir >= 3){
if(dir != sdir)
min = sy + y;
else
min = Math.abs(sy - y);
result += Math.abs(sx - x) + Math.min(min, 2 * n - min);
}
}
System.out.println(result);
br.close();
}
// 주어진 범위 안에 있는가
public static boolean isIn(int y, int x){
if(y < 0 || y > n || x < 0 || x > m)
return false;
return true;
}
// 방향과 떨어진 거리를 입력 받아, 좌표를 반환한다.
private static int[] point(int a, int b) {
switch(a) {
case 1:
return new int[] {0, b};
case 2:
return new int[] {n, b};
case 3:
return new int[] {b, 0};
case 4:
return new int[] {b, m};
}
return null;
}
static int stoi(String str) {
return Integer.parseInt(str);
}
}
총평
후기
처음 접근 하였을 때, 쉬운 문제였음에도 불구하고 접근하는 과정에서 갈팡질팡 하여 오래 걸려 자존심에 스크래치가 난 문제이다.
멘탈 관리 잘하자
개선할 점
없습니다.