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

 

10157번: 자리배정

첫 줄에는 공연장의 격자 크기를 나타내는 정수 C와 R이 하나의 공백을 사이에 두고 차례대로 주어진다. 두 값의 범위는 5 ≤ C, R ≤ 1,000이다. 그 다음 줄에는 어떤 관객의 대기번호 K가 주어진다.

www.acmicpc.net

 

문제

어떤 공연장에는 가로로 C개, 세로로 R개의 좌석이 C×R격자형으로 배치되어 있다. 각 좌석의 번호는 해당 격자의 좌표 (x,y)로 표시된다. 

예를 들어보자. 아래 그림은 가로 7개, 세로 6개 좌석으로 구성된 7×6격자형 좌석배치를 보여주고 있다. 그림에서 각 단위 사각형은 개별 좌석을 나타내며, 그 안에 표시된 값 (x,y)는 해당 좌석의 번호를 나타낸다. 가장 왼쪽 아래의 좌석번호는 (1,1)이며, 가장 오른쪽 위 좌석의 번호는 (7,6)이다. 

(1, 6)           (7, 6)
             
      (4, 4)     (7, 4)
(1, 3)         (6, 3)  
(1, 2)            
(1, 1) (2, 1) (3, 1)       (7, 1)

이 공연장에 입장하기 위하여 많은 사람이 대기줄에 서있다. 기다리고 있는 사람들은 제일 앞에서부터 1, 2, 3, 4, . 순으로 대기번호표를 받았다. 우리는 대기번호를 가진 사람들에 대하여 (1,1)위치 좌석부터 시작하여 시계방향으로 돌아가면서 비어있는 좌석에 관객을 순서대로 배정한다. 이것을 좀 더 구체적으로 설명하면 다음과 같다.

먼저 첫 번째 사람, 즉 대기번호 1인 사람은 자리 (1,1)에 배정한다. 그 다음에는 위쪽 방향의 좌석으로 올라가면서 다음 사람들을 배정한다. 만일 더 이상 위쪽 방향으로 빈 좌석이 없으면 오른쪽으로 가면서 배정한다. 오른쪽에 더 이상 빈자리가 없으면 아래쪽으로 내려간다. 그리고 아래쪽에 더 이상 자리가 없으면 왼쪽으로 가면서 남은 빈 좌석을 배정한다. 이 후 왼쪽으로 더 이상의 빈 좌석이 없으면 다시 위쪽으로 배정하고, 이 과정을 모든 좌석이 배정될 때까지 반복한다. 

아래 그림은 7×6공연장에서 대기번호 1번부터 42번까지의 관객이 좌석에 배정된 결과를 보여주고 있다.

6 7 8 9 10 11 12
5 26 27 28 29 30 13
4 25 38 39 40 31 14
3 24 37 42 41 32 15
2 23 36 35 34 33 16
1 22 21 20 19 18 17

여러분은 공연장의 크기를 나타내는 자연수 C와 R이 주어져 있을 때, 대기 순서가 K인 관객에게 배정될 좌석 번호 (x,y)를 찾는 프로그램을 작성해야 한다.

입력

첫 줄에는 공연장의 격자 크기를 나타내는 정수 C와 R이 하나의 공백을 사이에 두고 차례대로 주어진다. 두 값의 범위는 5 ≤ C, R ≤ 1,000이다. 그 다음 줄에는 어떤 관객의 대기번호 K가 주어진다. 단 1 ≤ K ≤ 100,000,000이다.

출력

입력으로 제시된 대기번호 K인 관객에게 배정될 좌석번호 (x,y)를 구해서 두 값, x와 y를 하나의 공백을 사이에 두고 출력해야 한다. 만일 모든 좌석이 배정되어 해당 대기번호의 관객에게 좌석을 배정할 수 없는 경우에는 0(숫자 영)을 출력해야 한다. 

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class BJ_10157 {
	static int[][] dir = { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } };

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine(), " ");
		int C = Integer.parseInt(st.nextToken());
		int R = Integer.parseInt(st.nextToken());
		int p = Integer.parseInt(br.readLine());

		if (R * C < p) {
			System.out.println(0);
			return;
		}
		int num = 0;
		int[][] arr = new int[R + 1][C + 1];
		for (int k = 0; k <= Integer.max(R, C); k++) {
			int t = 2 * k + 1;
			int borderlength = (R - t) * 2 + (C - t) * 2;
			if (borderlength == 0) {
				System.out.println(1+" " + 1);
				return;
			}
			if (p > num + borderlength) {
				num += borderlength;
				continue;
			}
			int x = k;
			int y = k + 1;
			int i = 0;
			int temp = 0;
			while (p != num) {
				num++;
				temp++;
				x += dir[i][0];
				y += dir[i][1];
				arr[x][y] = num;
				if (temp == R - 2 * k)
					i = 1;
				if (temp == R - 2 * k + C - 2 * k - 1)
					i = 2;
				if (temp == R - 2 * k + C - 2 * k - 1 + R - 2 * k - 1)
					i = 3;
			}
			System.out.println(y + " " + x);
			return;
		}
	}
}

 

 

둘레의 길이보다 크면 더 안쪽의 둘레로 들어가 수행 시간을 단축할 수 있도록 가장 바깥쪽 둘레부터 한칸씩 안쪽으로 검사해 주었습니다.

//둘레의 길이 borderlength

int borderlength = (R - t) * 2 + (C - t) * 2;

//예외 처리(1,1)인 경우(둘레의 길이가 0)
if (borderlength == 0) {
System.out.println(1+" " + 1);
return;
}

//검사(조건이 true면 안쪽으로 들어가기)
if (p > num + borderlength) {
num += borderlength;
continue;
}

 

더이상 안쪽으로 들어가지 않아도 된다면 이전 둘레의 마지막 좌표에서 시작하여

int x = k;
int y = k + 1;

 

temp가 경계에 닿으면 방향을 전환하도록 작성해주었습니다.

if (temp == R - 2 * k)
i = 1;
if (temp == R - 2 * k + C - 2 * k - 1)
i = 2;
if (temp == R - 2 * k + C - 2 * k - 1 + R - 2 * k - 1)
i = 3;

 

행과 열이 바뀌어 있으므로 출력은 y, x 순으로 출력하였습니다

'문제해결 > 백준' 카테고리의 다른 글

백준 2304번-창고 다각형(JAVA)  (0) 2021.08.25
백준 1753번-최단경로(JAVA)  (0) 2021.08.24
백준 15683번-감시(JAVA)  (0) 2021.08.20
백준 1987번-알파벳(JAVA)  (0) 2021.08.19
백준 1992번-쿼드트리(JAVA)  (0) 2021.08.18

+ Recent posts