지뢰찾기 게임에서 지뢰의 최대 개수를 찾는 알고리즘

9082번: 지뢰찾기

 

2*n 배열이 주어진다.

 

첫번째 행은 숫자들이 쓰여있는데 그 블록 주위에 지뢰가 몇개 있는지를 나타낸다.

 

두번째 행은 지뢰가 숨겨져 있는 행인데, *, #으로만 주어진다. *은 지뢰이다.

 

예를 들어 

 

11122

####*로 주어진다면

 

첫번째 #은 바로 위에 1이 쓰여있고, 우측 대각선 상단에 1이 쓰여있으므로 지뢰가 있을 수 있다.

 

11122

*###*

 

그리고 4번째 #에는 왼쪽 대각선 상단에 1, 바로 위 2, 우측 대각선 상단에 2가 쓰여있는 것으로 보아 지뢰가 있을 수 있다

 

11122

*##**

 

이때 *을 포함해서 숨겨진 지뢰의 최대 개수를 구한다.

 

----------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

0번의 숫자를 확인해보고, 0번의 숫자가 영향을 미칠 수 있는 곳에 있는 지뢰의 개수를 체크해본다

 

그리고 그에 맞게 지뢰를 설치한다

 

 

 

1번부터 n-2번까지 숫자를 확인해보고 마찬가지로 영향을 미칠 수 있는 곳에 있는 지뢰의 개수를 구한다.

 

그리고 그에 맞게 지뢰를 설치한다

 

 

 

보면 알겠지만 i번 숫자를 확인할 때는 0~i번까지는 지뢰가 확정되어 있다.

 

즉, i+1번의 지뢰만 결정하게 된다.

 

즉, i번의 숫자가 x라고 적혀있고, i번에 대하여 i-1번, i번, i+1번에 지뢰가 있는지 체크하게 될텐데,

 

현재 지뢰가 있는 개수가 count개라고 한다면, x-count개의 지뢰를 새로 설치해야한다.

 

그러면 i-1번, i번, i+1번 중 x-count개의 지뢰는 어디에 설치해야하는가?

 

이미 i-1,i번은 설치가 확정되어 있으므로, 반드시 i+1번에만 설치해야한다.

 

즉, x-count는 0 아니면 1이다.

 

이후 지뢰를 설치하면 다시 처음부터 순회해서 지뢰의 개수를 구하면 그것이 정답

 

from sys import stdin

T = int(stdin.readline())

for _ in range(T):
    
    n = int(stdin.readline())

    s1 = stdin.readline().rstrip()
    s2 = list(stdin.readline().rstrip())

    x = int(s1[0])

    count = 0

    for i in range(x):
        
        if s2[i] == '*':
            
            count += 1
    
    for i in range(x-count):
        
        s2[i] = '*'
    
    for i in range(1,n-1):
        
        x = int(s1[i])

        count = 0

        for j in range(i-1,i+1):
            
            if s2[j] == '*':
                
                count += 1
        
        r = x - count

        if r == 1:

            s2[i+1] = '*' 
        
    count = 0

    for i in range(n):
        
        if s2[i] == '*':
            
            count += 1
    
    print(count)

 

 

근데 조금 더 아름다운? 풀이가 있는데,

 

지뢰의 최대 개수가 m개라고 하자.

 

지뢰의 위치당 숫자의 총 합에 기여할 수 있는 양이 정해져있다.

 

양 끝쪽은 2만큼 기여할 수 있고, 1~n-1번은 3만큼 기여할 수 있다.

 

 

 

지뢰의 총 개수가 m개라고 할때, 양 끝 쪽에 있는 지뢰의 개수가 i개라고 한다면,

 

2i + 3(m-i) = (1행의 숫자 합)

 

1행의 숫자 합을 s라 하고 이것을 구한 다음 i = 0,1,2부터 해봐서 가능한 m의 최댓값을 찾으면 된다

 

이때 s - 2i가 3으로 나누어 떨어져야겠지

 

from sys import stdin

T = int(stdin.readline())

for _ in range(T):
    
    n = int(stdin.readline())

    s1 = list(map(int,input()))
    s2 = list(stdin.readline().rstrip())
    
    s = sum(s1)
    
    m = 0
    
    for i in range(3):
        
        #2*i + 3*(m-i) = s
        
        if (s-(2*i)) % 3 == 0:
            
            x = (s - (2*i))//3
            
            if m < x+i:
                
                m = x+i
    
    print(m)

 

 

----------------------------------------------------------------------------------------------------------------------------------------------------------

 

2140번: 지뢰찾기

 

이번엔 N*N 배열이 주어지는데, 테두리에 숫자들이 쓰여있고, 그 안쪽은 모두 #으로 닫혀있다.

 

이때, #에 존재할 수 있는 지뢰의 최대 개수를 찾는다.

 

숫자는 그 칸과 8방향으로 인접해 있는 곳에 있는 지뢰의 개수를 알려준다.

 

---------------------------------------------------------------------------------------------------------------------------------------------------------------

 

왼쪽 상단 대각선부터 시작해서, 시뮬레이션 하면서 지뢰를 설치할 수 있으면 일단 설치하면 된다.

 

 

 

각 지점에서 지뢰를 설치하는 경우, 8방향을 검사해서 숫자가 적힌 곳이면 1씩 빼줘야한다.

 

지뢰를 설치할 수 있는 곳은 어떤 곳인가?

 

8방향을 모두 검사해서, 숫자가 쓰여있는 곳이라면, 그 숫자들이 모두 1이상이어야 한다.

 

빨간색은 설치할 수 있는 곳인데

 

 

 

 

1이상인 숫자가 하나라도 없다면, 그곳에는 지뢰를 설치할 수 없다.

 

아래 파란색 동그라미 부분은 설치할 수 없는 곳이다

 

 

 

 

 

이렇게 하면, 숫자 테두리와 인접한 안쪽 테두리 부분은 지뢰를 모두 설치하게 된다.

 

 

 

 

이제 그 안쪽 부분은 아무런 제약조건이 없으므로, 지뢰의 최대 개수를 구해야하기 때문에 무조건 설치하면 된다. 

 

 

 

그 안쪽 부분은 몇개인가?

 

(n-4) * (n-4)개

 

 

 

 

그러면 예외가 생기게 된다

 

n = 1인 경우 1*1에는 숫자만 쓰여있으므로 지뢰가 없다 0개

 

n = 2인 경우도 마찬가지

 

n = 3인 경우는 안쪽이 1개만 있는데 모두 1로 쓰여있거나, 모두 0으로 쓰여있거나 둘중 하나여야 한다.

 

따라서 왼쪽 대각선 (0,0) 부분이 1이면 지뢰가 1개, 아니라면 지뢰가 0개

 

 

 

n=4부터는 위 방식대로 시뮬레이션 하면 된다

 

from sys import stdin

n = int(stdin.readline())

maps = [list(stdin.readline().rstrip()) for _ in range(n)]

if n <= 2:

    print(0)

else:
    
    if n == 3:
        
        if maps[0][0] == '1':
            
            print(1)
        
        else:
            
            print(0)
    
    else:

        maps[0] = list(map(int,maps[0]))
        maps[-1] = list(map(int,maps[-1]))

        for i in range(1,n-1):

            maps[i][0] = int(maps[i][0])
            maps[i][-1] = int(maps[i][-1])
        
        x,y = 1,1

        delta1 = [[1,0],[0,1],[-1,0],[0,-1]]
        delta2 = [[0,1],[1,0],[0,-1],[-1,0],[1,1],[1,-1],[-1,1],[-1,-1]]
        
        i = 0

        m = 0

        while 1:
            
            if maps[y][x] == '#':
                
                find = True

                for a,b in delta2:
                    
                    dx = x + a
                    dy = y + b

                    if maps[dy][dx] != '#' and maps[dy][dx] != '*':

                        if maps[dy][dx] == 0:
                        
                            find = False
                            break
                
                if find:
                    
                    for a,b in delta2:
                        
                        dx = x + a
                        dy = y + b

                        if maps[dy][dx] != '#' and maps[dy][dx] != '*':

                            if maps[dy][dx] >= 1:
                            
                                maps[dy][dx] -= 1
                    
                    maps[y][x] ='*'
                    m += 1

                a,b = delta1[i]

                x = x + a
                y = y + b

            if x == n-1 or y == n-1 or x == 0 or y == 0:
                
                x = x - a
                y = y - b

                i += 1

                a,b = delta1[i]

                x = x + a
                y = y + b
            
            if x == 1 and y == 1:
                
                break

        print(m + (n-4)*(n-4))

 

 

마찬가지로 위에서 2*n배열 풀때처럼 애드혹적인 방식으로도 해결 가능하다.

 

안쪽 테두리에서 모서리쪽에는 지뢰가 있는지 없는지 확신할 수 있다

 

(0,0), (0,-1), (-1,0), (-1,-1) 부분이 1인지 아닌지를 체크하면 된다.

 

이 부분은 오직 모서리쪽만 관여할 수 있으니까

 

 

 

 

이 4방향 꼭짓점 이외에는 나머지 부분은 모두 합에 3을 기여하게 된다

 

 

 

 

그래서 먼저 테두리 숫자 합을 s라 하자.

 

이제 꼭짓점 부분을 확인해서 확실하게 지뢰를 알 수 있는 곳을 체크한다.

 

(0,0)이 1인지, (0,-1)이 1인지, (-1,0)이 1인지, (-1,-1)이 1인지...

 

이제 지뢰가 있는 곳이라면 카운팅 해주고 합에 5를 빼주면 된다.

 

왜냐하면 꼭짓점 부분은 5방향에 기여하게 되니까

 

이렇게 체크하고 나서 변경된 합이 s라 한다면,

 

그리고 나머지 부분은 모두 합에 3을 기여하므로, 3m = s니까, m을 구할 수 있다.

 

이 m에다가 꼭짓점 부분 지뢰 개수 합에 나머지 안쪽 부분 (n-4)*(n-4)개를 더하면 그것이 정답

 

n = 1,2,3인 경우는 위에서 한 것처럼 예외처리

 

from sys import stdin

n = int(stdin.readline())

maps = [list(stdin.readline().rstrip()) for _ in range(n)]

if n <= 2:

    print(0)

else:

    s = 0

    s += sum(map(int,maps[0]))
    s += sum(map(int,maps[-1]))

    for i in range(1,n-1):

        s += (int(maps[i][0]) + int(maps[i][-1]))

    if n == 3:

        if s == 8:

            print(1)

        else:

            print(0)

    else:

        m = 0

        if maps[0][0] == '1':
            
            m += 1
            s -= 5
        
        if maps[0][-1] == '1':
            
            m += 1
            s -= 5
        
        if maps[-1][0] == '1':
            
            m += 1
            s -= 5
        
        if maps[-1][-1] == '1':
            
            m += 1
            s -= 5
        
        print(m + s//3 + (n-4)*(n-4))
728x90