반응형

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

 

13460번: 구슬 탈출 2

첫 번째 줄에는 보드의 세로, 가로 크기를 의미하는 두 정수 N, M (3 ≤ N, M ≤ 10)이 주어진다. 다음 N개의 줄에 보드의 모양을 나타내는 길이 M의 문자열이 주어진다. 이 문자열은 '.', '#', 'O', 'R', 'B'

www.acmicpc.net

문제 설명

위의 문제의 그림처럼 N * M 의 보드가 주어졌을 때, 빨간색 구슬을 구멍안에 넣는 게임이다.

파란색 구슬이 구멍안에 들어가서도 안되고,

굴리는 횟수가 10번을 넘어가서도 안된다.

 

여러가지 제약조건들이 많은 까다로운 BFS 문제이다.


풀이 과정

구슬을 굴리게 되면, 벽이나 구멍에 닿을 때 까지 구슬은 계속 굴러간다.

따라서, 방향 하나를 정했을 때 그 방향으로 계속 굴러가도록 while문을 통해 구슬을 굴려준다.

(코드의 roll함수의 while 부분)

 

또, 구슬이 굴러가다가 다른색의 구슬과 마주쳤을 경우에는

앞에 있는 구슬이 멈추면 내 구슬은 그 전칸에서 멈추게 되므로

각 구슬의 카운트를 통해 어떤 구슬이 앞에 있던 구슬인지 표기를 해준 후, 순서에 맞게 구슬을 배치하도록 한다.

 

또한, 4차원 visited 배열을 통해

발생했던 상황은 또 다시 발생하지 않도록 해준다.

 

2차원이 아닌 4차원 배열을 이용한 이유는

빨간색 구슬의 좌표는 이전과 같을지라도 파란색 구슬의 좌표가 다르다면 다른 상황이기 때문이다.

 

이를 파이썬 코드로 나타내면 다음과 같다.

from collections import deque

n, m = map(int, input().split())
graph = []
for i in range(n):
    graph.append(list(input()))

dx = [0, 0, 1, -1]
dy = [1, -1, 0, 0]
visited = [[[[False] * m for _ in range(n)] for _ in range(m)] for _ in range(n)]


def roll(x, y, direct):
    cnt = 0

    while graph[x + dx[direct]][y + dy[direct]] != '#' and graph[x][y] != 'O':
        x += dx[direct]
        y += dy[direct]
        cnt += 1

    return x, y, cnt


def bfs(ra, rb, ba, bb):
    queue = deque()
    queue.append((ra, rb, ba, bb, 1))

    while queue:
        rx, ry, bx, by, cnt = queue.popleft()
        visited[rx][ry][bx][by] = True

        if cnt > 10:
            print(-1)
            exit(0)

        for i in range(4):
            nrx, nry, rcnt = roll(rx, ry, i)
            nbx, nby, bcnt = roll(bx, by, i)

            if graph[nbx][nby] != 'O':
                if graph[nrx][nry] == 'O':
                    print(cnt)
                    exit(0)
				
                # 겹쳤을 때, 앞 뒤를 구분하여 재배치
                if nrx == nbx and nry == nby:
                    if rcnt > bcnt:
                        nrx -= dx[i]
                        nry -= dy[i]
                    else:
                        nbx -= dx[i]
                        nby -= dy[i]

                if not visited[nrx][nry][nbx][nby]:
                    visited[nrx][nry][nbx][nby] = True
                    queue.append((nrx, nry, nbx, nby, cnt+1))

    print(-1)
    return


rx, ry, bx, by = 0, 0, 0, 0
for i in range(n):
    for j in range(m):
        if graph[i][j] == 'R':
            rx = i
            ry = j
        if graph[i][j] == 'B':
            bx = i
            by = j

bfs(rx, ry, bx, by)

 

ps. 실패 코드

이 코드는 방문했던 지점을 다시 방문하게 되면서 히든 케이스들을 통과하지 못한 코드이다.

참고용으로 첨부해놓았다.

from collections import deque

n, m = map(int, input().split())
graph = []
for i in range(n):
    graph.append(list(input()))

dx = [0, 0, 1, -1]
dy = [1, -1, 0, 0]


def redBall(x, y, direct):
    nx = x + dx[direct]
    ny = y + dy[direct]
    while True:
        if nx < 0 or nx >= n or ny < 0 or ny >= m:
            break
        if graph[nx][ny] == '#':
            break
        if graph[nx][ny] == 'O':
            graph[x][y] = '.'
            return -1, -1
        if graph[nx][ny] == 'B':
            bx, by = blueBall(nx, ny, direct)
            if bx == nx and by == ny:
                graph[x][y] = '.'
                graph[nx-dx[direct]][ny - dy[direct]] = 'R'
                return nx - dx[direct], ny - dy[direct]
            if bx == -1 and by == -1:
                print(-1)
                exit(0)

        nx = nx + dx[direct]
        ny = ny + dy[direct]

    graph[x][y] = '.'
    graph[nx - dx[direct]][ny - dy[direct]] = 'R'

    return nx - dx[direct], ny - dy[direct]


def blueBall(x, y, direct):
    nx = x + dx[direct]
    ny = y + dy[direct]
    while True:
        if nx < 0 or nx >= n or ny < 0 or ny >= m:
            break
        if graph[nx][ny] == '#':
            break
        if graph[nx][ny] == 'O':
            return -1, -1
        if graph[nx][ny] == 'R':
            rx, ry = redBall(nx, ny, direct)
            if rx == nx and ry == ny:
                graph[x][y] = '.'
                graph[nx - dx[direct]][ny - dy[direct]] = 'B'
                return nx - dx[direct], ny - dy[direct]

        nx = nx + dx[direct]
        ny = ny + dy[direct]

    graph[x][y] = '.'
    graph[nx-dx[direct]][ny-dy[direct]] = 'B'

    return nx - dx[direct], ny - dy[direct]


def bfs(ra, rb, ba, bb):
    queue = deque()
    queue.append((ra, rb, ba, bb, 1))
    res = 1
    while queue:
        rx, ry, bx, by, cnt = queue.popleft()
        if cnt > 10:
            print(-1)
            exit(0)

        for i in range(4):
            nrx, nry = redBall(rx, ry, i)
            nbx, nby = blueBall(bx, by, i)
            if nrx == -1 and nry == -1:
                if nbx == -1 and nby == -1:
                    print(-1)
                    exit(0)
                else:
                    print(cnt)
                    exit(0)
            queue.append((nrx, nry, nbx, nby, cnt+1))

        res = cnt
    return res

rx, ry, bx, by = 0, 0, 0, 0
for i in range(n):
    for j in range(m):
        if graph[i][j] == 'R':
            rx = i
            ry = j
        if graph[i][j] == 'B':
            bx = i
            by = j

print(bfs(rx, ry, bx, by))

https://github.com/HongEunho

전체 문제 & 코드는 위의 깃에 정리되어 있습니다.

팔로우 & 맞팔은 환영입니다 !

반응형
반응형

https://programmers.co.kr/learn/courses/30/lessons/81302#fn1

 

코딩테스트 연습 - 거리두기 확인하기

[["POOOP", "OXXOX", "OPXPX", "OOXOX", "POXXP"], ["POOPX", "OXPXP", "PXXXO", "OXXXO", "OOOPP"], ["PXOPX", "OXOXP", "OXPOX", "OXXOP", "PXPOX"], ["OOOXX", "XOOOX", "OOOXX", "OXOOX", "OOOOO"], ["PXPXP", "XPXPX", "PXPXP", "XPXPX", "PXPXP"]] [1, 0, 1, 1, 1]

programmers.co.kr

문제 설명

대기실 상태가 그래프(배열)로 주어진다.

응시자 간 간격이 맨하튼 거리 2 이하인 경우를 방역수칙이 안지켜지고 있다고 하며

맨하튼 거리가 2 이상이거나 응시자 사이에 벽이 존재하는 경우 방역수칙을 지키고 있다고 한다.

 

대기실의 그래프가 주어졌을 때,

방역수칙을 지키고 있는지, 없는지를 확인하는 문제이다.


풀이 과정

이 문제를 카카오테스트에서 직접 풀었을 때는 DFS를 이용하였고

다시 풀 때는 BFS를 이용하였다.

 

BFS를 이용했을 때가 훨씬 간결하기도 하였고 풀이 방법도 더 좋은 것 같아

BFS를 이용해 풀이를 하려고 한다.

 

먼저 대기실은 5개 이며

각각의 대기실은 5 x 5 배열로 이루어져 있다.

 

그리고 1번째 대기실부터 확인해보자.

대기실에 응시자(P)가 발견되면 그 응시자를 기준으로 맨하튼 거리 이내에 BFS를 수행하여

거리두기가 지켜지고 있는지 확인하자.

 

먼저, bfs함수 내의 visited를 통해 한 번 방문했던 칸은 방문하지 않도록 할 것이다.

한번 더 방문하게 되면 while문을 두 번 돌았을 때, 맨하튼거리 2 이상을 보장하지 못한다.

ex) 오른쪽으로 갔다가 다시 왼쪽으로 오는 경우는 제자리

 

시작칸을 기준으로 bfs를 수행하며

거리 1(상하좌우) 이내에 'P'(또 다른 응시자)가 발견되면 즉시 False를 리턴하자.

방문한 지점이거나 벽이 있는 경우는 무시하자. ( 아직 거리두기를 침해하지 않았으므로 )

 

그 외에, 거리 1 이내에 'O'가 있는 경우는 다음 칸을 한 번 더 검사해야 하므로

그 지점을 큐에 넣어주자.

 

그리고, 처음 응시자(시작점) 기준으로 2바퀴를 돌았을 때는 맨하튼 거리 2를 넘어가게 되므로

이 때까지 False를 리턴하지 않았다면 거리두기를 잘 지킨 것이므로 True를 리턴해준다.

 

이렇게 각각의 P마다 bfs를 수행하여 그 대기실의 모든 P가 거리두기를 잘 지킨다면

그 대기실에 1을 표시한다.

from collections import deque

dx = [0, 0, 1, -1]
dy = [1, -1, 0, 0]

def bfs(candidate, place):
    queue = deque()
    visited = [[False]*5 for _ in range(5)]
    queue.append(candidate)
    cnt = 0
    
    while queue:
        x, y = queue.popleft()
        visited[x][y] = True
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if nx < 0 or nx >= 5 or ny < 0 or ny >= 5:
                continue
            if visited[nx][ny]:
                continue
            if place[nx][ny] == 'X':
                continue
            if place[nx][ny] == 'P':
                return False
            queue.append((nx, ny))
        
        cnt += 1
        if cnt == 2:
            return True
    return True
            

def solution(places):
    answer = []
    
    for place in places:
        candidates = deque()
        flag = True
        for i in range(5):
            for j in range(5):
                if place[i][j] == 'P':
                    candidates.append((i, j))
        
        for candidate in candidates:
            if not bfs(candidate, place):
                flag = False
                break
        
        if not flag:
            answer.append(0)
        else:
            answer.append(1)
        
    return answer

https://github.com/HongEunho

전체 문제 & 코드는 위의 깃에 정리되어 있습니다.

팔로우 & 맞팔은 환영입니다 !

반응형
반응형

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

 

1149번: RGB거리

첫째 줄에 집의 수 N(2 ≤ N ≤ 1,000)이 주어진다. 둘째 줄부터 N개의 줄에는 각 집을 빨강, 초록, 파랑으로 칠하는 비용이 1번 집부터 한 줄에 하나씩 주어진다. 집을 칠하는 비용은 1,000보다 작거나

www.acmicpc.net

문제 설명

RGB거리에는 집이 N개 있다. 거리는 선분으로 나타낼 수 있고, 1번 집부터 N번 집이 순서대로 있다.

집은 빨강, 초록, 파랑 중 하나의 색으로 칠해야 한다. 각각의 집을 빨강, 초록, 파랑으로 칠하는 비용이 주어졌을 때, 아래 규칙을 만족하면서 모든 집을 칠하는 비용의 최솟값을 구해보자.

  • 1번 집의 색은 2번 집의 색과 같지 않아야 한다.
  • N번 집의 색은 N-1번 집의 색과 같지 않아야 한다.
  • i(2 ≤ i ≤ N-1)번 집의 색은 i-1번, i+1번 집의 색과 같지 않아야 한다.

풀이 과정

이 문제는 DP(다이나믹 프로그래밍)을 이용해 앞에서 부터 최소값을 저장해 나가며

모든 집을 칠했을 때의 최소값을 구하는 문제이다.

 

먼저 Nx3 모양의 2차원 DP배열을 만들어

R, G, B 페인트를 칠했을 때의 최솟값들을 저장해주자.

예를 들어, DP[N][0]은 현재 N번집에 R 페인트를 칠했을 때의 최솟값을 저장하게 된다.

 

첫 집은 R, G, B 모두를 선택할 수 있으므로

DP[0][0]에는 첫 번째 집의 R비용을,

DP[0][1]에는 첫 번째 집의 G비용을,

DP[0][2]에는 첫 번째 집의 B비용을 각각 저장하자.

 

두 번째 집부터, 바로 전집과는 다른 색을 칠해야 하므로

두번째 집에 R을 선택했다면 이전집에서는 G,B 를 칠한 것 중 최솟값을 선택하여 더하면 된다.

 

이러한 방식으로 값을 누적해나가 마지막 집의 DP값을 구하면 답을 구할 수 있다.

n = int(input())

cost = []
minCost = -int(1e9)
dp = [[0]*3 for _ in range(n)]
for i in range(n):
    cost.append(list(map(int, input().split())))

dp[0][0], dp[0][1], dp[0][2] = cost[0][0], cost[0][1], cost[0][2]

for i in range(1, n):
    dp[i][0] = min(dp[i-1][1] + cost[i][0], dp[i-1][2] + cost[i][0])
    dp[i][1] = min(dp[i-1][0] + cost[i][1], dp[i-1][2] + cost[i][1])
    dp[i][2] = min(dp[i-1][0] + cost[i][2], dp[i-1][1] + cost[i][2])

print(min(dp[n-1][0], dp[n-1][1], dp[n-1][2]))

https://github.com/HongEunho

전체 문제 & 코드는 위의 깃에 정리되어 있습니다.

팔로우 & 맞팔은 환영입니다 !

반응형
반응형

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

 

1904번: 01타일

지원이에게 2진 수열을 가르쳐 주기 위해, 지원이 아버지는 그에게 타일들을 선물해주셨다. 그리고 이 각각의 타일들은 0 또는 1이 쓰여 있는 낱장의 타일들이다. 어느 날 짓궂은 동주가 지원이

www.acmicpc.net

문제 설명

지원이에게 2진 수열을 가르쳐 주기 위해, 지원이 아버지는 그에게 타일들을 선물해주셨다. 그리고 이 각각의 타일들은 0 또는 1이 쓰여 있는 낱장의 타일들이다.

어느 날 짓궂은 동주가 지원이의 공부를 방해하기 위해 0이 쓰여진 낱장의 타일들을 붙여서 한 쌍으로 이루어진 00 타일들을 만들었다. 결국 현재 1 하나만으로 이루어진 타일 또는 0타일을 두 개 붙인 한 쌍의 00타일들만이 남게 되었다.

그러므로 지원이는 타일로 더 이상 크기가 N인 모든 2진 수열을 만들 수 없게 되었다. 예를 들어, N=1일 때 1만 만들 수 있고, N=2일 때는 00, 11을 만들 수 있다. (01, 10은 만들 수 없게 되었다.) 또한 N=4일 때는 0011, 0000, 1001, 1100, 1111 등 총 5개의 2진 수열을 만들 수 있다.

우리의 목표는 N이 주어졌을 때 지원이가 만들 수 있는 모든 가짓수를 세는 것이다. 단 타일들은 무한히 많은 것으로 가정하자.


풀이 과정

이 문제에는 다음과 같은 규칙이 존재한다.

DP[1] = 1 ( 1 )

DP[2] = 2 ( 11 , 00 )

DP[3] = 3 ( 111, 100, 001)

DP[4] = 5 ( 1111, 1100, 1001, 1100, 0000 )

 

위 결과를 보면 알 수 있듯이 DP[n]은 DP[n-1] + DP[n-2] 의 형식으로 쌓아가는 것을 볼 수 있다.

 

1은 단독으로 쓰일 수 있지만 0은 단독으로 쓰일 수 없기 때문에

현재 결과에 '1' 만을 붙여 다음값을 만들 수 있지만

'0'만을 붙여 다음값을 만들 수 없으므로 '00'을 붙여 다음 값을 만들게 된다.

하지만 '00'은 길이가 2 이므로 현재값에 붙이면 길이가 초과하게 되므로 이전값에 붙여주어야 한다.

 

예를 들어,

DP[4]의 경우에는

DP[3]의 각각의 값에 1을 붙인 것과

DP[2]의 각각의 값에 00을 붙인 것과 같다.

 

이 특징을 살려 코드를 구현하면 다음과 같다.

 

다만, 문제의 n이 최대 1,000,000 이므로 계산 중간 int의 범위를 벗어나는 경우가 생기므로

맨 마지막 결과가 아닌 중간중간 %15746을 해야한다.

n = int(input())

dp = [0]*(n+1)
dp[1] = 1
dp[2] = 2

for i in range(3, n+1):
    dp[i] = (dp[i-1] + dp[i-2]) % 15746

print(dp[n])

https://github.com/HongEunho

전체 문제 & 코드는 위의 깃에 정리되어 있습니다.

팔로우 & 맞팔은 환영입니다 !

반응형
반응형

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

 

9184번: 신나는 함수 실행

입력은 세 정수 a, b, c로 이루어져 있으며, 한 줄에 하나씩 주어진다. 입력의 마지막은 -1 -1 -1로 나타내며, 세 정수가 모두 -1인 경우는 입력의 마지막을 제외하면 없다.

www.acmicpc.net

문제 설명

if a <= 0 or b <= 0 or c <= 0, then w(a, b, c) returns:
    1

if a > 20 or b > 20 or c > 20, then w(a, b, c) returns:
    w(20, 20, 20)

if a < b and b < c, then w(a, b, c) returns:
    w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c)

otherwise it returns:
    w(a-1, b, c) + w(a-1, b-1, c) + w(a-1, b, c-1) - w(a-1, b-1, c-1)

이러한 재귀함수 w를 수행시간이 짧아지도록 구현하는 문제이다.


풀이 과정

문제에서 주어진 재귀함수의 수행시간이 오래걸리는 이유는 매번 값을 계산하기 때문이다.

한 번 계산된 값도 다음에 다시 계산이 된다.

그래서 매번 값을 계산하도록 하는 형식이 아닌 한 번 계산된 값은 저장하도록 하면 된다.

그래서 DP를 이용하자.

 

문제에서 주어진 조건문은 그대로 구현을 해주면 된다.

단지, 계산된 값만 3차원 DP배열에 저장을 해줌으로써 재 계산을 할 필요가 없도록 하면 된다.

import sys
dp = [[[0]*21 for _ in range(21)] for _ in range(21)]

def w(a, b, c):
    if a <= 0 or b <= 0 or c <= 0:
        return 1
    if a > 20 or b > 20 or c > 20:
        return w(20, 20, 20)

    if dp[a][b][c]:
        return dp[a][b][c]

    if a < b < c:
        dp[a][b][c] = w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c)
        return dp[a][b][c]

    dp[a][b][c] = w(a-1, b, c) + w(a-1, b-1, c) + w(a-1, b, c-1) - w(a-1, b-1, c-1)
    return dp[a][b][c]

while True:
    a, b, c = map(int, sys.stdin.readline().rstrip().split())
    if a == -1 and b == -1 and c == -1:
        break
    ans = w(a, b, c)
    print("w(%d, %d, %d) = %d" %(a, b, c, ans))

https://github.com/HongEunho

전체 문제 & 코드는 위의 깃에 정리되어 있습니다.

팔로우 & 맞팔은 환영입니다 !

반응형
반응형

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

 

14889번: 스타트와 링크

예제 2의 경우에 (1, 3, 6), (2, 4, 5)로 팀을 나누면 되고, 예제 3의 경우에는 (1, 2, 4, 5), (3, 6, 7, 8)로 팀을 나누면 된다.

www.acmicpc.net

문제 설명

문제에서 n이 주어지고 1부터 n까지 차례대로 번호가 붙은 사람 n명이 존재한다.

이 n명의 사람을 두 팀으로 나눈 후 각 팀의 시너지의 합을 구하게 되는데

시너지는 문제에서 입력으로 주어진다.

n x n 형식의 배열로 주어지며 배열[1][2] 는 1과 2가 한팀일 때의 시너지를 나타낸다.

 

이 때, 두 팀의 시너지의 합의 최소값을 구하는 문제이다.


풀이 과정

이 문제는 두 팀의 시너지 차이의 최소값을 구해야 하므로 모든 시너지를 탐색해야 하는 브루트포스 문제이다.

 

따라서 다음과 같이 접근하였다.

① 조합(Combinations)을 이용해 모든 경우의 수(팀)를 구한다.

    n = 6 이면 6개 중에서 순서를 고려하지 않고 3개를 뽑는 경우의 수와 같다.

    그러면 팀 1 : [1, 2, 3] / 팀 2: [4, 5, 6] 등과 같이 팀을 구할 수 있다.

 

② 각 경우의 수에 대해 팀의 시너지를 구한다.

    위의 예시에서는, 팀1의 경우에는 graph[1][2] + graph[1][3] + graph[2][1] ... + graph[3][2] 를 구하고

    팀2의 경우에는 graph[4][5] + graph[4][6] + ... graph[6][5] 를 구하면 된다.

 

③ 두 팀의 시너지의 차이와 현재 최소값과 비교해

    현재 차이가 더 작다면 최소값을 현재 차이로 교체한다.

 

이를 파이썬 코드로 나타내면 다음과 같다.

from itertools import combinations

n = int(input())
graph = []
number = [i for i in range(n)]

minR = int(1e9)

for i in range(n):
    graph.append(list(map(int, input().split())))


for c in combinations(number, n//2):
    visited = [False] * n
    team1 = []
    team2 = []
    for i in c:
        visited[i] = True
        team1.append(i)

    for i in range(n):
        if not visited[i]:
            team2.append(i)

    sum1 = 0
    sum2 = 0
    for i in range(n//2):
        for j in range(n//2):
            if graph[team1[i]][team1[j]] != 0:
                sum1 += graph[team1[i]][team1[j]]
            if graph[team2[i]][team2[j]] != 0:
                sum2 += graph[team2[i]][team2[j]]

    if abs(sum1-sum2) < minR:
        minR = abs(sum1-sum2)

print(minR)

https://github.com/HongEunho

전체 문제 & 코드는 위의 깃에 정리되어 있습니다.

팔로우 & 맞팔은 환영입니다 !

반응형
반응형

문제 설명

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

 

14888번: 연산자 끼워넣기

첫째 줄에 수의 개수 N(2 ≤ N ≤ 11)가 주어진다. 둘째 줄에는 A1, A2, ..., AN이 주어진다. (1 ≤ Ai ≤ 100) 셋째 줄에는 합이 N-1인 4개의 정수가 주어지는데, 차례대로 덧셈(+)의 개수, 뺄셈(-)의 개수, 

www.acmicpc.net

주어진 숫자와 연산자로 만들 수 있는 수식의 결과값 중 최대값과 최소값을 구하면 됩니다.


풀이 과정

이 문제는 DFS와 백트래킹을 이용했다.

 

문제에서 연산에 사용할 숫자(A1,A2...An)와 연산자의 개수(b1, b2, b3, b4)가 주어진다.

연산자는 앞에서 부터 차례대로 더하기, 빼기, 곱하기, 나누기 연산자의 개수를 나타낸다

숫자의 순서는 바뀌면 안되며, 연산자의 순서만을 바꿀 수 있다.

 

따라서, 숫자의 순서는 유지한채 연산자를 더하기, 빼기, 곱하기, 나누기를 써가며 식을 바꿔주면 되므로

첫 번째 숫자에 첫 연산자를 넣고 DFS를 돌린다음

다시 백트래킹을 통해 원래 상태로 돌린 후

두 번째 연산자를 넣고 DFS를 돌린다음 다시 백트래킹으로 원래 상태로 돌려

모든 경우의 수를 찾아내야 한다.

 

그리고 이 모든 경우의 수 중에 최댓값과 최솟값을 찾아 출력하면 된다.

이를 파이썬 코드로 나타내면 다음과 같다.

n = int(input())
number = list(map(int, input().split()))
op = list(map(int, input().split()))
minR = int(1e9)
maxR = -int(1e9)

answer = number[0]

def dfs(idx):
    global answer
    global minR, maxR

    if idx == n:
        if answer > maxR:
            maxR = answer
        if answer < minR:
            minR = answer
        return

    for i in range(4):
        tmp = answer
        if op[i] > 0:
            if i == 0:
                answer += number[idx]
            elif i == 1:
                answer -= number[idx]
            elif i == 2:
                answer *= number[idx]
            else:
                if answer >= 0:
                    answer //= number[idx]
                else:
                    answer = (-answer // number[idx]) * -1

            op[i] -= 1
            dfs(idx+1)
            answer = tmp
            op[i] += 1


dfs(1)
print(maxR)
print(minR)

https://github.com/HongEunho

전체 문제 & 코드는 위의 깃에 정리되어 있습니다.

팔로우 & 맞팔은 환영입니다 !

반응형
반응형

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

 

2580번: 스도쿠

스도쿠는 18세기 스위스 수학자가 만든 '라틴 사각형'이랑 퍼즐에서 유래한 것으로 현재 많은 인기를 누리고 있다. 이 게임은 아래 그림과 같이 가로, 세로 각각 9개씩 총 81개의 작은 칸으로 이루

www.acmicpc.net

문제 설명

스도쿠가 주어졌을 때, 빈 칸을 채워 스도쿠를 완성하는 문제이다.


풀이 과정

문제를 풀기전에, 스도쿠가 무엇인지에 대해 먼저 알아야 한다.

자세한 설명은 위 백준 문제링크에 나와있지만

9 x 9 맵에서 가로(행)에 1~9까지 모든 숫자가 들어가야 하고 세로(열)에도 1~9까지의 모든 숫자가 들어가야하고

3x3 정사각형에도 1~9까지의 모든 숫자가 들어가야 한다.

 

그래서 맵이 주어졌을 때

첫 번째 빈 칸부터 시작하여 마지막 빈 칸까지 적절한 수를 넣어가며 스도쿠를 완성시켜야 한다.

그래서 DFS + 백트래킹을 통해

첫 번째 칸에 1~9 숫자를 넣어가며 확인하면 된다.

 

풀이 방법은 다음과 같다.

 

① 먼저 문제에서 빈 칸은 0으로 주어지기 때문에

graph의 0인칸의 위치정보(x, y)를 blank 리스트에 넣어준다.

 

② 첫 번째 빈칸에 1~9까지의 수 중 넣을 수 있는 수를 넣는다.

넣을 수 있는 수는 빈칸의 행,열,3x3정사각형에 없는 수임을 확인하자.

확인이 되면 그 빈칸에는 그 수를 넣어준다.

 

③ 그 다음 빈칸에 대해서도 같은 방법을 수행한다.

 

④ 마지막 빈칸까지 채우면 스도쿠를 완성하므로 맵을 출력한다.

 

import sys
graph = []
blank = []

for i in range(9):
    graph.append(list(map(int, sys.stdin.readline().rstrip().split())))

for i in range(9):
    for j in range(9):
        if graph[i][j] == 0:
            blank.append((i, j))

def checkRow(x, a):
    for i in range(9):
        if a == graph[x][i]:
            return False
    return True

def checkCol(y, a):
    for i in range(9):
        if a == graph[i][y]:
            return False
    return True

def checkRect(x, y, a):
    nx = x // 3 * 3
    ny = y // 3 * 3
    for i in range(3):
        for j in range(3):
            if a == graph[nx+i][ny+j]:
                return False
    return True


def dfs(idx):
    if idx == len(blank):
        for i in range(9):
            print(*graph[i])
        exit(0)

    for i in range(1, 10):
        x = blank[idx][0]
        y = blank[idx][1]

        if checkRow(x, i) and checkCol(y, i) and checkRect(x, y, i):
            graph[x][y] = i
            dfs(idx+1)
            graph[x][y] = 0

dfs(0)

https://github.com/HongEunho

전체 문제 & 코드는 위의 깃에 정리되어 있습니다.

팔로우 & 맞팔은 환영입니다 !

반응형

+ Recent posts