문제
가로 A(1≤A≤100), 세로 B(1≤B≤100) 크기의 땅이 있다. 이 땅 위에 로봇들이 N(1≤N≤100)개 있다.
로봇들의 초기 위치는 x좌표와 y좌표로 나타난다. 위의 그림에서 보듯 x좌표는 왼쪽부터, y좌표는 아래쪽부터 순서가 매겨진다. 또한 각 로봇은 맨 처음에 NWES 중 하나의 방향을 향해 서 있다. 초기에 서 있는 로봇들의 위치는 서로 다르다.
이러한 로봇들에 M(1≤M≤100)개의 명령을 내리려고 한다. 각각의 명령은 순차적으로 실행된다. 즉, 하나의 명령을 한 로봇에서 내렸으면, 그 명령이 완수될 때까지 그 로봇과 다른 모든 로봇에게 다른 명령을 내릴 수 없다. 각각의 로봇에 대해 수행하는 명령은 다음의 세 가지가 있다.
- L: 로봇이 향하고 있는 방향을 기준으로 왼쪽으로 90도 회전한다.
- R: 로봇이 향하고 있는 방향을 기준으로 오른쪽으로 90도 회전한다.
- F: 로봇이 향하고 있는 방향을 기준으로 앞으로 한 칸 움직인다.
간혹 로봇들에게 내리는 명령이 잘못될 수도 있기 때문에, 당신은 로봇들에게 명령을 내리기 전에 한 번 시뮬레이션을 해 보면서 안전성을 검증하려 한다. 이를 도와주는 프로그램을 작성하시오.
잘못된 명령에는 다음의 두 가지가 있을 수 있다.
- Robot X crashes into the wall: X번 로봇이 벽에 충돌하는 경우이다. 즉, 주어진 땅의 밖으로 벗어나는 경우가 된다.
- Robot X crashes into robot Y: X번 로봇이 움직이다가 Y번 로봇에 충돌하는 경우이다.
입력
첫째 줄에 두 정수 A, B가 주어진다. 다음 줄에는 두 정수 N, M이 주어진다. 다음 N개의 줄에는 각 로봇의 초기 위치(x, y좌표 순) 및 방향이 주어진다. 다음 M개의 줄에는 각 명령이 명령을 내리는 순서대로 주어진다. 각각의 명령은 명령을 내리는 로봇, 명령의 종류(위에 나와 있는), 명령의 반복 회수로 나타낸다. 각 명령의 반복 회수는 1이상 100이하이다.
출력
첫째 줄에 시뮬레이션 결과를 출력한다. 문제가 없는 경우에는 OK를, 그 외의 경우에는 위의 형식대로 출력을 한다. 만약 충돌이 여러 번 발생하는 경우에는 가장 먼저 발생하는 충돌을 출력하면 된다.
풀이
회전 동작의 경우, 4바퀴를 돌면 원래 방향으로 돌아오기에 mod연산자를 이용하여 N%4의 값만 회전한다.
전진 동작의 경우, 한칸씩 확인하면서 충돌하는지 판단을 해야하기에 하나씩 이동한다.
들어오는 로봇은 robots를 이용하여 위치를 저장해놓고 현재의 위치와 보고 있는 방향을 저장하였고,
충돌판단을 쉽게하기 위해서 positions를 이용하여 좌표에 있는 로봇들의 위치 정보를 표현하였음
현 문제에서는 배열의 방향이 위아래로 뒤집혀서 디버깅시 표현되는 형태와 반대이기에
디버깅시 편하도록 행의 번호를 반대로 생각해서 구현하였다.
자세한 사항은 코드 참고
코드
import java.io.*;
import java.util.*;
public class Main {
static int a,b,n,m;
static int [][] robots, positions;
static int [] dx, dy;
public static void main(String[] args) throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
a=Integer.parseInt(st.nextToken());
b=Integer.parseInt(st.nextToken());
positions = new int[b+1][a+1]; // 행렬의 크기를 반대로 연산
st = new StringTokenizer(br.readLine());
n=Integer.parseInt(st.nextToken());
m=Integer.parseInt(st.nextToken());
robots = new int[n+1][3]; // 로봇의 위치정보 방향정보를 기억
// L회전을 기준으로 동 북 서 남 방향으로 회전
dx=new int[] {0,1,0,-1};
dy=new int[] {1,0,-1,0};
for(int i=1;i<=n;i++)
{
st = new StringTokenizer(br.readLine());
int x, y; // X와 Y를 반대로 입력받아서 연산
y=Integer.parseInt(st.nextToken());
x=Integer.parseInt(st.nextToken());
robots[i][0]=x;
robots[i][1]=y;
char ch=st.nextToken().charAt(0);
int dir=0;
if(ch=='E') // 동쪽을 보고있다면 dx, dy의 인덱스는 0
dir=0;
else if(ch=='N')
dir=1;
else if(ch=='W')
dir=2;
else if(ch=='S')
dir=3;
robots[i][2]=dir;
positions[x][y]=i; // positions에 로봇이 존재하는지 값으로 표현
}
boolean chk=false;
for(int i=0;i<m;i++) {
st = new StringTokenizer(br.readLine());
int robot = Integer.parseInt(st.nextToken()); // 명령어에서 로봇의 번호를 입력
char command = st.nextToken().charAt(0); // 로봇이 움직일 명령어
int rep = Integer.parseInt(st.nextToken()); // 반복횟수
if(command=='F')
chk = forward(robot, rep);
else if(command=='L') // 회전시 4번돌면 원래 방향으로 회귀
robots[robot][2]=(robots[robot][2]+rep%4)%4; // %연산을 이용하여 4의 반복횟수를 무시
else if(command=='R')
robots[robot][2]=(4-rep%4+robots[robot][2])%4; // 반대로 돌면 역연산이 일어나기 때문에, 4에서 도는 횟수만큼 반대로 연산하도록 계싼
if(chk)
break;
}
if(!chk)
System.out.println("OK");
}
// Forward 이동의 경우 하나하나 움직이면서 충돌하는지 연산을 해야함
static public boolean forward(int robot, int rep) {
int x=robots[robot][0], y=robots[robot][1], dir=robots[robot][2];
positions[x][y]=0; // 로봇을 이동하기 때문에, 현재 있는 로봇의 존재를 맵에서 삭제
for(int i=0;i<rep;i++) {
x+=dx[dir]; // 로봇이 바라보고 있는 방향으로 이동
y+=dy[dir];
if(x<1 || x>b || y<1 || y>a) { // 범위를 벗어난다면 벽에 박았다는 의미
System.out.printf("Robot %d crashes into the wall", robot);
return true;
}
if(positions[x][y]!=0) { // 이동한 위치가 0이 아니라면 다른 로봇이 존재한다는 의미임
System.out.printf("Robot %d crashes into robot %d", robot, positions[x][y]);
return true;
}
}
robots[robot][0]=x; // 위치정보를 업데이트
robots[robot][1]=y;
positions[x][y]=robot; // 지도에 로봇위치를 저장
return false;
}
}
'Algorithm > Baekjoon' 카테고리의 다른 글
Baekjoon 6118 숨바꼭질 JAVA (0) | 2022.06.10 |
---|---|
Baekjoon 5567 결혼식 JAVA (0) | 2022.06.10 |
Baekjoon 1002 터렛 JAVA (0) | 2022.06.10 |
Baekjoon 10844 쉬운 계단 수 JAVA (0) | 2022.06.10 |
Baekjoon 1100 하얀 칸 JAVA (0) | 2022.06.09 |
댓글