백준 10703번: 유성 [Python]

실버 I 실버 I

문제

유성
제한 때문에 약간 까다로운 구현 문제입니다.

풀이

유성의 표면이 땅에 떨어지기 까지 몇 칸 움직여야 하는지 계산하고, 나머지 픽셀들을 한꺼번에 옮겨주면 됩니다.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
class Meteor:
    def __init__(self, pic: list[list[str]]):
        self.pic = pic
        self.r, self.c = len(pic), len(pic[0])
        self.surface = [None] * s
        self.grounds = set()
        self.fall_dist = 0

        for i in range(self.r - 1, -1, -1):
            for j in range(self.c):
                if self.surface[j] is None and self.pic[i][j] == "X":
                    self.surface[j] = i
                    self.pic[i][j] = "."
                elif pic[i][j] == "#":
                    self.grounds.add((i, j))

    def fall(self) -> bool:
        """
        유성을 한 픽셀 아래로 떨어뜨리고,
        만약 떨어뜨릴 수 없다면 False를 반환합니다.
        """

        new_surface = self.surface.copy()
        for j, i in enumerate(self.surface):
            if i is None:
                continue
            if (i + 1, j) in self.grounds:
                return False
            new_surface[j] = i + 1
        self.surface = new_surface
        self.fall_dist += 1
        return True

    def print(self) -> None:
        for i in range(self.r - 1, -1, -1):
            for j in range(self.c):
                if self.pic[i][j] == "X":
                    self.pic[i + self.fall_dist][j] = "X"
                    self.pic[i][j] = "."

        for j, i in enumerate(self.surface):
            if i is None:
                continue
            self.pic[i][j] = "X"

        for row in self.pic:
            print(*row, sep="")


r, s = map(int, input().split())

meteor = Meteor([list(input()) for _ in range(r)])
while meteor.fall():
    ...
meteor.print()

백준 10703번: 유성 [Python]