https://www.acmicpc.net/problem/2477
문제
시골에 있는 태양이의 삼촌 댁에는 커다란 참외밭이 있다. 문득 태양이는 이 밭에서 자라는 참외가 도대체 몇 개나 되는지 궁금해졌다. 어떻게 알아낼 수 있는지 골똘히 생각하다가 드디어 좋은 아이디어가 떠올랐다. 유레카! 1m^2의 넓이에 자라는 참외 개수를 헤아린 다음, 참외밭의 넓이를 구하면 비례식을 이용하여 참외의 총개수를 구할 수 있다.
1m^2의 넓이에 자라는 참외의 개수는 헤아렸고, 이제 참외밭의 넓이만 구하면 된다. 참외밭은 ㄱ-자 모양이거나 ㄱ-자를 90도, 180도, 270도 회전한 모양(┏, ┗, ┛ 모양)의 육각형이다. 다행히도 밭의 경계(육각형의 변)는 모두 동서 방향이거나 남북 방향이었다. 밭의 한 모퉁이에서 출발하여 밭의 둘레를 돌면서 밭 경계 길이를 모두 측정하였다.
예를 들어 참외밭이 위 그림과 같은 모양이라고 하자. 그림에서 오른쪽은 동쪽, 왼쪽은 서쪽, 아래쪽은 남쪽, 위쪽은 북쪽이다. 이 그림의 왼쪽위 꼭짓점에서 출발하여, 반시계 방향으로 남쪽으로 30m, 동쪽으로 60m, 남쪽으로 20m, 동쪽으로 100m, 북쪽으로 50m, 서쪽으로 160m 이동하면 다시 출발점으로 되돌아가게 된다.
위 그림의 참외밭 면적은 6800m2이다. 만약 1m^2의 넓이에 자라는 참외의 개수가 7이라면, 이 밭에서 자라는 참외의 개수는 47600으로 계산된다.
1m^2의 넓이에 자라는 참외의 개수와, 참외밭을 이루는 육각형의 임의의 한 꼭짓점에서 출발하여 반시계 방향으로 둘레를 돌면서 지나는 변의 방향과 길이가 순서대로 주어진다. 이 참외밭에서 자라는 참외의 수를 구하는 프로그램을 작성하시오.
입력
첫 번째 줄에 1m2의 넓이에 자라는 참외의 개수를 나타내는 양의 정수 K (1 ≤ K ≤ 20)가 주어진다. 참외밭을 나타내는 육각형의 임의의 한 꼭짓점에서 출발하여 반시계 방향으로 둘레를 돌면서 지나는 변의 방향과 길이 (1 이상 500 이하의 정수)가 둘째 줄부터 일곱 번째 줄까지 한 줄에 하나씩 순서대로 주어진다. 변의 방향에서 동쪽은 1, 서쪽은 2, 남쪽은 3, 북쪽은 4로 나타낸다.
출력
첫째 줄에 입력으로 주어진 밭에서 자라는 참외의 수를 출력한다.
풀이🚀
문제를 읽고나서 ㄱ자 육각형의 넓이를 구하기 위해 큰 사각형의 넓이에서 작은 사각형의 넓이만 빼면 되는 간단한 문제라고 생각했지만, 생각보다 작은 사각형의 넓이를 구하기가 까다로웠다.
우선 입력받은 방향과, 변의 길이를 좌표로 변환했다.
임의의 꼭지점에서 시작하기 때문에 좌표계에 표현할 때는 항상 시작점을 원점(0, 0)으로 시작했다.
7
4 50
2 160
3 30
1 60
3 20
1 100
예를 들어 입력이 위와 같을 때, 좌표로 변환하면 아래와 같이 표현된다.
여기서 X좌표의 최댓값과 최소값을 구한 뒤 둘의 차이를 구하면 큰 사각형의 한 변의 길이가 되고
Y좌표도 동일하게 구하면 다른 한 변이 되므로 큰 사각형의 넓이를 구할 수 있다.
작은 사각형의 넓이를 구학 위해서는 중간에 꺾여있는 점 (-100, 20) 의 좌표를 먼저 구해야 하므로
X, Y 좌표의 최댓값과 최솟값 사이를 만족하는 점이 위의 점임을 이용하여 구했다.
중간 점의 좌표를 구했으므로 서로 이어진 점 두개 (-160, 20), (-100, 0)을 구하여 작은 사각형의 넓이를 구했다.
큰 사각형에서 작은 사각형의 넒이를 뺀 뒤 1m^2 당 참외의 개수를 곱해주면 참외의 수가 나온다.
뭔가 수학적으로 간결하게 풀어 낼 수 있을 것 같지만 그러지 못해 아쉬웠다...
코드
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;
public class Main {
final static int E = 1;
final static int W = 2;
final static int S = 3;
final static int N = 4;
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st;
int K = Integer.parseInt(br.readLine());
Point[] pList = new Point[6];
Point prev = new Point(0, 0);
for (int i = 0; i < 6; i++) {
st = new StringTokenizer(br.readLine());
int dir = Integer.parseInt(st.nextToken());
int len = Integer.parseInt(st.nextToken());
switch (dir) { // 좌표로 변환
case E:
pList[i] = new Point(prev.x + len, prev.y);
break;
case W:
pList[i] = new Point(prev.x - len, prev.y);
break;
case S:
pList[i] = new Point(prev.x, prev.y - len);
break;
case N:
pList[i] = new Point(prev.x, prev.y + len);
break;
}
prev = pList[i];
}
int maxX = Integer.MIN_VALUE, minX = Integer.MAX_VALUE;
int maxY = Integer.MIN_VALUE, minY = Integer.MAX_VALUE;
int midX = 0, midY = 0;
for (int i = 0; i < 6; i++) { // 각 X, Y의 최대값, 최소값 구하기
if (maxX < pList[i].x) {
maxX = pList[i].x;
}
if (minX > pList[i].x) {
minX = pList[i].x;
}
if (maxY < pList[i].y) {
maxY = pList[i].y;
}
if (minY > pList[i].y) {
minY = pList[i].y;
}
}
for (int i = 0; i < 6; i++) { // 중간 점 구하기
if (pList[i].x > minX && pList[i].x < maxX) {
midX = pList[i].x;
}
if (pList[i].y > minY && pList[i].y < maxY) {
midY = pList[i].y;
}
}
int lenX = 0, lenY = 0;
for (int i = 0; i < 6; i++) { // 중간점을 통해 작은 사각형의 각 변의 길이 구하기
if (pList[i].x == midX && pList[i].y != midY) {
lenY = Math.max(pList[i].y, midY) - Math.min(pList[i].y, midY);
}
if (pList[i].y == midY && pList[i].x != midX) {
lenX = Math.max(pList[i].x, midX) - Math.min(pList[i].x, midX);
}
}
int big = (maxX - minX) * (maxY - minY); // 큰 사각형의 넓이
int small = lenX * lenY; // 작은 사각형의 넓이
bw.write(String.valueOf((big - small) * K));
bw.flush();
bw.close();
br.close();
}
}
class Point { // 좌표 표현을 위한 Point 클래스
int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
'Algorithm > 백준' 카테고리의 다른 글
[백준] 21609. 상어 중학교 (Java, 자바) (0) | 2022.11.29 |
---|---|
[백준] 14226. 이모티콘 (Java, 자바) (0) | 2022.11.23 |
[백준] 17142. 연구소 3 (Java, 자바) (0) | 2022.11.22 |
[백준] 2559. 수열 (Java, 자바) (0) | 2022.02.09 |
[백준] 1244. 스위치 켜고 끄기 (Java, 자바) (0) | 2022.02.09 |