백준

[백준_1913번] 달팽이

빙수빈수 2021. 8. 20. 19:58

https://www.acmicpc.net/problem/1913

 

1913번: 달팽이

N개의 줄에 걸쳐 표를 출력한다. 각 줄에 N개의 자연수를 한 칸씩 띄어서 출력하면 되며, 자릿수를 맞출 필요가 없다. N+1번째 줄에는 입력받은 자연수의 좌표를 나타내는 두 정수를 한 칸 띄어서

www.acmicpc.net

[문제]

홀수인 자연수 N이 주어지면, 다음과 같이 1부터 N2까지의 자연수를 달팽이 모양으로 N×N의 표에 채울 수 있다.

9 2 3
8 1 4
7 6 5

 

25 10 11 12 13
24 9 2 3 14
23 8 1 4 15
22 7 6 5 16
21 20 19 18 17

 

 N이 주어졌을 때, 이러한 표를 출력하는 프로그램을 작성하시오. 또한 N2 이하의 자연수가 하나 주어졌을 때, 그 좌표도 함께 출력하시오. 예를 들어 N=5인 경우 6의 좌표는 (4,3)이다.

 

[입력 조건]

첫째 줄에 홀수인 자연수 N(3 ≤ N ≤ 999)이 주어진다. 둘째 줄에는 위치를 찾고자 하는 N2 이하의 자연수가 하나 주어진다.

 

[코드]

import java.io.*;
import java.util.*;

public class BaekJoon_1913 {
	// n*n 숫자는 시계 반대 방향으로 줄어든다.
	static int[] dx= {1,0,-1,0};
	static int[] dy= {0,1,0,-1};
	public static void main(String[] args) throws Exception {
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st=new StringTokenizer(br.readLine());
		StringBuilder sb=new StringBuilder();
		
		int n=Integer.parseInt(st.nextToken());
		
		st=new StringTokenizer(br.readLine());
		int m=Integer.parseInt(st.nextToken());
		
		int[][] arr=new int[n][n];
		int num=n*n; // 배열의 (0,0)은 n*n 부터 시작
		int x=0,y=0,direction=0,px=0,py=0;
		
		while(num>0) {
			int nx=x+dx[direction]; // 다음 좌표 계산
			int ny=y+dy[direction];
			
			/*
			 * 방향이 바뀌는 지점은 배열의 범위를 벗어나거나 
			 * 배열에 이미 값이 들어있는 경우이다. 따라서 다음 좌표를 계산했을 때
			 * 해당 조건에 만족하면 방향을 변경하여 좌표를 계산해야 한다. 
			 */
			if(nx<0||nx>=n||ny>=n||ny<0||arr[nx][ny]!=0) {
				direction++; // 방향 변겅
				if(direction==4)
					direction=0;
				
				// 변경한 방향으로 다시 다음 좌표 계산
				nx=x+dx[direction]; 
				ny=y+dy[direction];
			}
			
			arr[x][y]=num--; // 숫자 저장
			x=nx; // 다음 좌표로 갱신
			y=ny;
		}
		
		for(int i=0;i<n;i++){
			for(int j=0;j<n;j++) {
				// m의 값을 갖는 행,열 찾기
				if(arr[i][j]==m) {
					px=i;
					py=j;
				}
				sb.append(arr[i][j]+" ");
			}
			/*
			 * m의 값을 갖는 행,열을 바로 출력하기 위해 
			 * 마지막 행은 줄바꿈을 하지 않는다.
			 */
			if(i==n-1)
				continue;
			sb.append('\n');
		}
		
		System.out.println(sb); // 배열 출력
		System.out.println((px+1)+" "+(py+1)); // m의 위치를 1행, 1열로 바꿔 출력(각 값에 +1하기)
	}

}

 

[고찰]

 이번 문제는 배열의 가운데부터 시계방향으로 숫자를 늘려 채워나가는 문제이다. 배열의 가운데부터 시작하려니 인덱스 계산이 어려워 배열의 (0,0) 부터 시작하였다. 배열의 (0,0)은 n*n 숫자부터 시계 반대방향으로 숫자가 줄어나가는 형태를 띈다.

 다음으로 중요한 것은 언제 방향이 바뀌느냐이다. 다음 좌표가 배열의 범위를 벗어나거나 이미 배열에 값이 저장되있는 경우 방향을 회전해야한다. 따라서 숫자를 저장 후 다음 좌표를 계산했을 때 배열 범위를 벗어나거나, 이미 배열에 값이 저장되 있다면 방향을 바꿔주고 다시 좌표 값을 계산해준다. 

 처음에는 Scanner를 사용하고, 배열 값을 2중 for문을 사용하여 출력해주었는데 시간초과를 받았다. 이를 해결하기 위해 BufferedReader와 StringBuilder를 사용했다.

'백준' 카테고리의 다른 글

[백준_9205번] 맥주 마시면서 걸어가기  (0) 2021.08.22
[백준_2468번] 안전 영역  (0) 2021.08.21
[백준_1316번] 그룹 단어 체커  (0) 2021.08.20
[백준_2636번] 치즈  (0) 2021.08.20
[백준_10971번] 외판원 순회 2  (0) 2021.08.20