Search

BAEKJOON 2563 색종이

카테고리
Algorithm
태그
BAEKJOON
게시일
2023/03/17
수정일
2024/02/24 09:41
시리즈
1 more property
들어가기 앞서, 문제를 이해하는 것이 얼마나 중요한지 다시 한 번 깨닫게 되는 문제였습니다. 이 문제를 풀면서 헷갈리고 방향을 잘못 잡았다는 점을 리뷰하고자 글을 작성하였습니다.

Challenge

문제를 요약하면, 정해진 넓이(도화지)내의 색종이를 여러장 받아서 놓고, 전체 넓이를 구하는 문제입니다.
N개의 좌표가 주어집니다.
좌표에서부터 10 x 10의 종이가 있고, 그 종이는 절대 도화지 밖으로 벗어나지 않습니다.
종이는 겹칠 수 있고, 여러 개가 동시에 겹칠 수도 있습니다.

Description

가로, 세로의 크기가 각각 100인 정사각형 모양의 흰색 도화지가 있다. 이 도화지 위에 가로, 세로의 크기가 각각 10인 정사각형 모양의 검은색 색종이를 색종이의 변과 도화지의 변이 평행하도록 붙인다. 이러한 방식으로 색종이를 한 장 또는 여러 장 붙인 후 색종이가 붙은 검은 영역의 넓이를 구하는 프로그램을 작성하시오.
예를 들어 흰색 도화지 위에 세 장의 검은색 색종이를 그림과 같은 모양으로 붙였다면 검은색 영역의 넓이는 260이 된다.

Inputs

첫째 줄에 색종이의 수가 주어진다. 이어 둘째 줄부터 한 줄에 하나씩 색종이를 붙인 위치가 주어진다. 색종이를 붙인 위치는 두 개의 자연수로 주어지는데 첫 번째 자연수는 색종이의 왼쪽 변과 도화지의 왼쪽 변 사이의 거리이고, 두 번째 자연수는 색종이의 아래쪽 변과 도화지의 아래쪽 변 사이의 거리이다. 색종이의 수는 100 이하이며, 색종이가 도화지 밖으로 나가는 경우는 없다 * Examples 1 3 3 7 15 7 5 2
Plain Text
복사

Outputs

첫째 줄에 색종이가 붙은 검은 영역의 넓이를 출력한다. * Examples 1 260
Plain Text
복사

Solve

문제 풀이로 요구하는 내용은, N개의 색종이가 주어지고 100 x 100의 도화지에 올라가 덮어진 전체 색종이 넓이를 구하는 것입니다.

Issues

처음에 문제를 풀 때, 내용을 잘못 이해하고 있었던 점이 있습니다. 색종이가 겹치는 부분에 대해서만 집중하고 전체적인 문제 내용을 파악하지 못했었습니다. 때문에 다음과 같은 알고리즘이 나오게 됐습니다.

Failed

아래의 풀이에서 사용한 알고리즘은 두 개의 사각형이 겹쳤을 때 겹치는 영역에 대한 정보를 계산하는 방법을 적용해보았습니다. 다만 이 방법을 적용하고자 할 때, 몇 번이고 겹칠 수 있기 때문에 while문을 통해 더이상 겹치는 영역이 없는지 확인하여 계산을 끝내는 방식입니다.
1.
전체 사각형의 넓이를 더하고
2.
겹치는 부분의 x, y, w, h 정보를 통해 중복되어 겹치는 부분을 저장합니다.
3.
홀수 번째로 검사한 겹치는 부분의 넓이는 빼고, 짝수 번째로 검사한 겹치는 부분의 넓이는 더해줍니다.
4.
더 이상 겹치는 부분이 없을 때까지 2번~ 3번 과정을 반복합니다.
5.
결과를 출력합니다.
이와 같은 방법은 중복된 겹치는 부분은 제외하고, 전체 겹치는 넓이를 계산하는 방법으로 알고리즘을 계산하였습니다. 단, 이렇게 구현할 경우, 겹치는 부분이 얼마나 있을지 알 수 없기 때문에 계산식이 매우 오래걸릴 수 있습니다. 색종이의 수가 100개이고 최대 회수로 겹치는 영역이 있다면, 최대 100!(팩토리얼) 회수 만큼 계산이 필요할 것으로 보입니다. 따라서 해당 알고리즘으로는 풀이가 불가능하였습니다.
import sys import itertools N = int(sys.stdin.readline().strip()) done = False width, height = 10, 10 rectangles = [] answer = (width*height)*N repeated = 1 def get_intersection_area(r1, r2): # x: 0, y: 1, w: 2, h: 3 if r1[0] > r2[0] + r2[2]: return None, 0 elif r1[0] + r2[2] < r2[0]: return None, 0 elif r1[1] > r2[1] + r2[3]: return None, 0 elif r1[1] + r1[3] < r2[1]: return None, 0 x = max(r1[0], r2[0]) y = max(r1[1], r2[1]) w = min(r1[0] + r1[2], r2[0] + r2[2]) - x h = min(r1[1] + r1[3], r2[1] + r2[3]) - y return [(x, y, w, h), w*h] for __ in range(N): # x, y, w, h rectangles.append([int(i) for i in sys.stdin.readline().strip().split(" ")] + [width, height]) if N == 1: print(width * height) else: while not done: _tmp = [] if len(rectangles) <= 1: done = True break for r1, r2 in itertools.combinations(rectangles, 2): rect, area = get_intersection_area(r1, r2) if not rect: continue if repeated % 2: answer -= area else: answer += area _tmp.append(rect) rectangles = _tmp print(answer)
Python
복사

Success

아래의 알고리즘은 100 x 100의 영역을 2차원 배열로 설정하고, 각 좌표별로 1을 세팅하는 방법으로 구현하였습니다. 해당 방법으로 구현할 경우, 겹치는 부분에 1로 다시 한 번 덮어씌우더라도 넓이 계산에 중복이 없다는 점을 이용하였습니다. 이러한 조건이 가능한 이유로는 100 x 100의 영역이라는 조건이 있기 때문에 가능한 것이라고 생각됩니다.
import sys # Initialization w, h = 10, 10 paper = [] for __ in range(100): paper.append([0 for __ in range(100)]) # Solve N = int(sys.stdin.readline().strip()) for __ in range(N): x, y = [int(i) for i in sys.stdin.readline().strip().split(" ")] for _w in range(w): for _h in range(h): paper[x+_w-1][_h+y-1] = 1 total = 0 for p in paper: # print(" ".join([str(_p) for _p in p])) total += sum(p) print(total)
Python
복사

Reviews

문제를 풀 때 알고리즘을 구현하는 것에 급급할 것이 아니라 문제를 인지하고 어떠한 방법으로 푸는 것이 좋은지 적절한 연구가 필요하다는 것을 다시 한 번 깨닫게 되었습니다. 무엇보다 문제를 정확하게 파악하는 것만큼 중요한 것은 없다는 점을 뼈저리게 느꼈습니다. 실패한 알고리즘을 설계할 때 100 x 100 도화지에 대한 조건을 중요하게 생각하지 않아 문제를 잘못된 방향으로 풀고자 하고, 그 만큼 시간을 많이 소요하게 되었습니다.

References