728x90

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

 

1759번: 암호 만들기

첫째 줄에 두 정수 L, C가 주어진다. (3 ≤ L ≤ C ≤ 15) 다음 줄에는 C개의 문자들이 공백으로 구분되어 주어진다. 주어지는 문자들은 알파벳 소문자이며, 중복되는 것은 없다.

www.acmicpc.net

아무 생각 없이 풀어서 한 번 틀렸다.

 

우선 입력받은 배열을 바로 정렬하고, 그 배열로 부분집합을 만드는 것까지는 바로 생각이 난다.

 

하지만 그렇게 만든 부분집합에서 조건으로 걸러야 한다.

 

make_key(cur_candidate + [candidate[index]], index + 1)
make_key(cur_candidate, index + 1)

 

이렇게 재귀함수로 현재의 값을 추가하는 집합 하나, 추가하지 않는 집합 하나를 만들어준다.

def make_key(cur_candidate, index):

    if index == C:
        value = len(set(cur_candidate).intersection(important))
        if len(cur_candidate) == L and value >= 1 and (L - value) >= 2:
            for i in cur_candidate:
                print(i, end='')
            print()
            return

    else:
        make_key(cur_candidate + [candidate[index]], index + 1)
        make_key(cur_candidate, index + 1)

 

이렇게 하나씩 추가하다가 인덱스가 C를 넘어갔을 때, 현재 부분집합의 길이가 L이고 모음이 하나 이상 있고 자음이 2개 이상 있을 때만 출력이 되도록 해줬다.

import sys

L, C = map(int, sys.stdin.readline().split())

candidate = sorted(list(map(str, sys.stdin.readline().split())))

important = {'a', 'e', 'i', 'o', 'u'}


def make_key(cur_candidate, index):

    if index == C:
        value = len(set(cur_candidate).intersection(important))
        if len(cur_candidate) == L and value >= 1 and (L - value) >= 2:
            for i in cur_candidate:
                print(i, end='')
            print()
            return

    else:
        make_key(cur_candidate + [candidate[index]], index + 1)
        make_key(cur_candidate, index + 1)


make_key([], 0)

'알고리즘 > 브루트포스' 카테고리의 다른 글

백준 14501 퇴사  (0) 2024.01.15
백준 1182 부분수열의 합  (0) 2024.01.15
백준 4675 셀프 넘버  (1) 2024.01.15
백준 1065 한수  (0) 2024.01.15
게임판 덮기  (0) 2022.09.17
728x90

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

 

14501번: 퇴사

첫째 줄에 백준이가 얻을 수 있는 최대 이익을 출력한다.

www.acmicpc.net

 

브루트포스 문제들을 모아서 풀다가 풀어보니 크게 어렵지 않게 풀 수 있었다.

 

간단하게 해당 일정을 추가하는 것과 안추가 하는 것들을 비교해보면 된다.

물론 이 방법도 경우의 수가 엄청 많이 나올 것이다.

 

def consult(today, cur):
    if today == N:
        return cur
    elif today > N:
        return 0
    else:
        return max(consult(today + 1, cur), consult(today + schedule_list[today][0], cur + schedule_list[today][1]))

 

사용한 함수이다.

만약 today가 딱 N 안으로 끝났다면 더 이상 추가할 수 없으니, 그냥 현재의 이익을 반환한다.

만약 today가 N을 벗어났다면, 해당 스케줄은 사용할 수 없는 스케줄이니 그냥 0을 반환해버린다.

 

위의 2가지 경우 모두 해당되지 않는다면, 해당 스케줄을 추가하는 것과 추가하지 않는 것을 다시 재귀함수에 넣어서 그 중 큰 값을 반환한다.

 

import sys

N = int(sys.stdin.readline())

schedule_list = []

for i in range(N):
    T, P = map(int, sys.stdin.readline().split())
    schedule_list.append([T, P])


def consult(today, cur):
    if today == N:
        return cur
    elif today > N:
        return 0
    else:
        return max(consult(today + 1, cur), consult(today + schedule_list[today][0], cur + schedule_list[today][1]))


print(consult(0, 0))

'알고리즘 > 브루트포스' 카테고리의 다른 글

백준 1759 암호 만들기  (1) 2024.01.15
백준 1182 부분수열의 합  (0) 2024.01.15
백준 4675 셀프 넘버  (1) 2024.01.15
백준 1065 한수  (0) 2024.01.15
게임판 덮기  (0) 2022.09.17
728x90

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

 

1182번: 부분수열의 합

첫째 줄에 정수의 개수를 나타내는 N과 정수 S가 주어진다. (1 ≤ N ≤ 20, |S| ≤ 1,000,000) 둘째 줄에 N개의 정수가 빈 칸을 사이에 두고 주어진다. 주어지는 정수의 절댓값은 100,000을 넘지 않는다.

www.acmicpc.net

그냥 부분집합 만들고, 그 부분집합이 S인지 확인하면 끝난다.

물론 방법은 쉽지만, 경우가 많이 나오기 때문에 신경쓰지 않으면 시간초과가 날 거 같기도 하다.

 

딱히 생각나는 방법은 없어서 재귀함수로 풀었다.

 

def find(param_list, cur_num):
    if len(param_list) == 0:
        if cur_num == S:
            return 1
        else:
            return 0

    return find(param_list[1:], cur_num + param_list[0]) + find(param_list[1:], cur_num)

 

각 수마다 넣을 지 말지에 대해서 2가지 경우의 수로 나누고, 선택할 수 있는 수가 없을 때의 합을 구해서 S가 맞는 지 확인한다.

지금 작성하면서 보니까 cur_num을 안쓰고 그냥 sum(list)로 했으면 더 깔끔했을 거 같다.

 

이렇게 하면 길이가 5개 일 때, 32가지의 경우가 나오게 된다.

 

하지만 이렇게 구하면 답은 맞지 않을거다.

공집합의 경우의 수도 포함하여 0을 반환하기 때문에 해당 경우는 빼주어야 한다.

import sys

N, S = map(int, sys.stdin.readline().split())

input_list = list(map(int, sys.stdin.readline().split()))


def find(param_list, cur_num):
    if len(param_list) == 0:
        if cur_num == S:
            return 1
        else:
            return 0

    return find(param_list[1:], cur_num + param_list[0]) + find(param_list[1:], cur_num)


result = find(input_list, 0)

if S == 0:
    print(result - 1)
else:
    print(result)

공집합은 0이기 때문에 S가 0일 때만 빼주도록 하자.

'알고리즘 > 브루트포스' 카테고리의 다른 글

백준 1759 암호 만들기  (1) 2024.01.15
백준 14501 퇴사  (0) 2024.01.15
백준 4675 셀프 넘버  (1) 2024.01.15
백준 1065 한수  (0) 2024.01.15
게임판 덮기  (0) 2022.09.17
728x90

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

 

4673번: 셀프 넘버

셀프 넘버는 1949년 인도 수학자 D.R. Kaprekar가 이름 붙였다. 양의 정수 n에 대해서 d(n)을 n과 n의 각 자리수를 더하는 함수라고 정의하자. 예를 들어, d(75) = 75+7+5 = 87이다. 양의 정수 n이 주어졌을 때,

www.acmicpc.net

해당 문제는 입력이 없다...

그래서 그냥 바로 배열 출력해도 답은 맞을 거 같기도 하다.

그래도 일단 풀어보자.

 

처음에 헷갈린 부분인데, 10 미만의 수는 그 수 자체가 되는 것인 줄 알았다.

하지만 2, 4, 6, 8... 이렇게는 셀프 넘버가 아닌 것을 보고 d(1) = 1 + 1 = 2가 된다는 것을 깨닫고 풀 수 있게 되었다.

만약 푸는 중간에 알게 되었다면 고생 좀 했을 것 같다.

 

우선 d(n)에 대한 함수를 만들어주자.

def d(n):
    d_result = n

    while n > 9:
        d_result += (n % 10)
        n //= 10

    return d_result + n

 

해당 수와 쪼갠 수들을 모두 더해서 반환해주는 d(n) 함수이다.

 

result = [True for i in range(1, 10001)]

def d(n):
    d_result = n

    while n > 9:
        d_result += (n % 10)
        n //= 10

    return d_result + n


for i in range(1, 10000):
    if result[i]:
        print(i)
        num = i
        while num < 10000:
            num = d(num)
            if num < 10000:
                result[num] = False

 

1부터 10000까지 반복을 하면서 만약 result[i]에 대한 수가 True라면 해당 수를 출력하고, 그 수로 만들 수 있는 수들을 연쇄적으로 모두 지워준다.

'알고리즘 > 브루트포스' 카테고리의 다른 글

백준 14501 퇴사  (0) 2024.01.15
백준 1182 부분수열의 합  (0) 2024.01.15
백준 1065 한수  (0) 2024.01.15
게임판 덮기  (0) 2022.09.17
소풍  (1) 2022.09.16
728x90

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

 

1065번: 한수

어떤 양의 정수 X의 각 자리가 등차수열을 이룬다면, 그 수를 한수라고 한다. 등차수열은 연속된 두 개의 수의 차이가 일정한 수열을 말한다. N이 주어졌을 때, 1보다 크거나 같고, N보다 작거나

www.acmicpc.net

 

가장 먼저 생각해본 부분은 100미만의 수이다.

만약 0~9라면 무조건 비교할 수가 없기에 무조건 한수가 될 것이다.

만약 10~99라면 수가 2개 밖에 되지 않기 때문에 무조건 한수가 될 것이다.

 

그렇기 때문에 해당 수들은 모두 한수로 처리를 해주고 들어가야 한다.

def hansoo(num):
    hansoo_list = []
    while num > 0:
        hansoo_list.append(num % 10)
        num //= 10
    for t in range(len(hansoo_list) - 2):
        if hansoo_list[t+1] - hansoo_list[t] != hansoo_list[t+2] - hansoo_list[t+1]:
            return False
    return True

 

우선 해당 수가 한수인지 판별해주는 함수이다.

만약 100 미만의 수가 들어오면 배열의 크기가 2 이하가 되기 때문에 무조건 True가 반환되게 된다.

 

100 이상의 수가 들어오게 된다면, 해당 수를 모두 쪼개서 배열에 저장한다.

그리고 반복문을 통해 간격이 다른 구간이 있다면 바로 False를 반환한다.

 

import sys

N = int(sys.stdin.readline())

result = 0


def hansoo(num):
    hansoo_list = []
    while num > 0:
        hansoo_list.append(num % 10)
        num //= 10
    for t in range(len(hansoo_list) - 2):
        if hansoo_list[t+1] - hansoo_list[t] != hansoo_list[t+2] - hansoo_list[t+1]:
            return False

    return True

for i in range(1, N + 1):
    if hansoo(i):
        result += 1

print(result)

 

이렇게 전체 코드이다.

입력한 수에 따라 반복문으로 한수의 개수를 찾아서 출력하게 된다.

 

'알고리즘 > 브루트포스' 카테고리의 다른 글

백준 1182 부분수열의 합  (0) 2024.01.15
백준 4675 셀프 넘버  (1) 2024.01.15
게임판 덮기  (0) 2022.09.17
소풍  (1) 2022.09.16
보글 게임  (1) 2022.09.16
728x90
 

GitHub - Seungkyu-Han/PS_strategy: 알고리즘 분류하는 워크플레이스

알고리즘 분류하는 워크플레이스. Contribute to Seungkyu-Han/PS_strategy development by creating an account on GitHub.

github.com

 

 

algospot.com :: BOARDCOVER

게임판 덮기 문제 정보 문제 H*W 크기의 게임판이 있습니다. 게임판은 검은 칸과 흰 칸으로 구성된 격자 모양을 하고 있는데 이 중 모든 흰 칸을 3칸짜리 L자 모양의 블록으로 덮고 싶습니다. 이

www.algospot.com

게임판 덮기 문제이다.

알고스팟에 제출을 해봤는데 nonzero return code...?? 라는 에러가 뜬다.

어차피 제출할 용도가 아닌 공부용이었으니 풀어보기만 하고 제출은 하지 않도록 하겠다.

 

좌표를 모두 돌며 확인하는 브루트포스 + 해당 경우에서 더 이상 답을 찾지 못하면 돌아오는 백트래킹 방법이다.

이 문제를 풀고 생각난 건데 브루트포스는 완전탐색이다. 따라서 확인 할 수 있는 모든 경우를 찾아야 한다.

이 문제에서도 놓을 수 있는 블록의 타입을 모두 찾아야 정답이 나온다.

만약 경우를 모두 찾지 못하면 정답보다 작은 값이, 경우를 중복으로 찾았다면 정답보다 큰 값이 나오게 될 것이다.

 

이 문제에서 좌표를 x, y라고 했을 때, 놓을 수 있는 블록의 종류이다.

block = [[[0, 0], [1, 0], [0, 1]], [[0, 0], [0, 1], [1, 1]], [[0, 0], [1, 0], [1, 1]], [[0, 0], [1, 0], [1, -1]]]​

 

당연히 해당 좌표를 비우고 간다면 모든 게임판을 채울 수 없게 되고, 이 이외의 블록 종류들은 다른 칸에서 놓는 블록의 모양과 중복이 된다.

 

게임판을 받았을 때 다음으로 채워야 하는 좌표를 반환해주는 함수이다. 

def find(h_len, w_len):
    for q in range(h_len):
        for r in range(w_len):
            if board_list[q][r] == '.':
                return [q, r]
    return [-1, -1]  # 모든 칸이 덮여있으면

모든 칸에 블록이 있다면 -1, -1을 리턴해주어 호출한 곳에 알려준다.

 

게임판에 해당 타입의 종류의 블록을 놓을 수 있는지 알려주는 함수이다.

def is_blank(x, y, block_type):
    for q in range(3):
        if 0 <= x + block[block_type][q][0] < h and 0 <= y + block[block_type][q][1] < w:
            if board_list[x + block[block_type][q][0]][y + block[block_type][q][1]] == '#':
                return False
    return True

 

게임판을 '#'으로 덮어주거나, '.'으로 치워주는 함수이다.

def cover_block(x, y, block_type, blank_or_block):
    for q in range(3):
        board_list[x + block[block_type][q][0]][y + block[block_type][q][1]] = blank_or_block

백트래킹에서는 정답의 경우가 없으면 복구를 해줘야 하기 때문에 blank_or_block으로 '.'도 받아서 복구도 할 수 있도록 하였다.

block_type으로 블록의 종류를 받고 해당 칸 만큼 채워주거나 치워준다.

 

def solve(board_list, h, w):
    global result
    result = 0

    # 놓을 수 있는 블록의 종류
    block = [[[0, 0], [1, 0], [0, 1]], [[0, 0], [0, 1], [1, 1]], [[0, 0], [1, 0], [1, 1]], [[0, 0], [1, 0], [1, -1]]]

    def cover():
        global result

        x, y = find(h, w)
        if x == -1 and y == -1:
            result += 1
            return

        for q in range(4):
            if is_blank(x, y, q):
                cover_block(x, y, q, '#')
                cover()
                cover_block(x, y, q, '.')

    def find(h_len, w_len):
        for q in range(h_len):
            for r in range(w_len):
                if board_list[q][r] == '.':
                    return [q, r]
        return [-1, -1]  # 모든 칸이 덮여있으면

    def is_blank(x, y, block_type):
        for q in range(3):
            if 0 <= x + block[block_type][q][0] < h and 0 <= y + block[block_type][q][1] < w:
                if board_list[x + block[block_type][q][0]][y + block[block_type][q][1]] == '#':
                    return False
        return True

    def cover_block(x, y, block_type, blank_or_block):
        for q in range(3):
            board_list[x + block[block_type][q][0]][y + block[block_type][q][1]] = blank_or_block

    cover()
    print(result)

사용한 함수의 전체이다.

 

함수 안에 함수들을 넣어서 최대한 깔끔하게 정답을 리턴할 수 있도록 했다.

cover() 함수에서 find를 좌표들을 돌며 채워주고 복구해주는 백트래킹 방법을 사용했다.

만약 find()에서 -1, -1을 리턴받으면 외부 전역 변수 result에 +1을 해준다.

 

import sys

result = 0


def solve(board_list, h, w):
    global result
    result = 0

    # 놓을 수 있는 블록의 종류
    block = [[[0, 0], [1, 0], [0, 1]], [[0, 0], [0, 1], [1, 1]], [[0, 0], [1, 0], [1, 1]], [[0, 0], [1, 0], [1, -1]]]

    def cover():
        global result

        x, y = find(h, w)
        if x == -1 and y == -1:
            result += 1
            return

        for q in range(4):
            if is_blank(x, y, q):
                cover_block(x, y, q, '#')
                cover()
                cover_block(x, y, q, '.')

    def find(h_len, w_len):
        for q in range(h_len):
            for r in range(w_len):
                if board_list[q][r] == '.':
                    return [q, r]
        return [-1, -1]  # 모든 칸이 덮여있으면

    def is_blank(x, y, block_type):
        for q in range(3):
            if 0 <= x + block[block_type][q][0] < h and 0 <= y + block[block_type][q][1] < w:
                if board_list[x + block[block_type][q][0]][y + block[block_type][q][1]] == '#':
                    return False
        return True

    def cover_block(x, y, block_type, blank_or_block):
        for q in range(3):
            board_list[x + block[block_type][q][0]][y + block[block_type][q][1]] = blank_or_block

    cover()
    print(result)


for _ in range(int(sys.stdin.readline())):
    H, W = map(int, sys.stdin.readline().split())

    board = []
    blank_cnt = 0

    for i in range(H):
        board.append(list(sys.stdin.readline().strip()))
        blank_cnt += board[-1].count('.')

    # 빈칸의 수가 3의 배수가 아니면 어차피 덮지 못하니 continue
    if blank_cnt % 3 != 0:
        print(0)
        continue

    solve(board, H, W)

사용한 코드의 전체이다.

 

브루트포스에서 가장 중요한 것은 탐색할 수 있는 모든 경우의 수를 찾는 것이다.

항상 생각하고 풀 수 있도록 하자!

'알고리즘 > 브루트포스' 카테고리의 다른 글

백준 4675 셀프 넘버  (1) 2024.01.15
백준 1065 한수  (0) 2024.01.15
소풍  (1) 2022.09.16
보글 게임  (1) 2022.09.16
조합을 구하는 알고리즘  (0) 2022.09.15
728x90
 

GitHub - Seungkyu-Han/PS_strategy: 알고리즘 분류하는 워크플레이스

알고리즘 분류하는 워크플레이스. Contribute to Seungkyu-Han/PS_strategy development by creating an account on GitHub.

github.com

이전에도 풀었던 문제이지만 알고리즘을 복습하면서 다시 풀어보았다.

백준을 위해서 푼 건 아니지만 백준에 문제가 있기는 하다.

 

2026번: 소풍

만약 K명의 친구 관계인 학생들이 존재하지 않는다면 -1을 출력한다. 그 외의 경우에는, K개의 줄에 학생들의 번호를 증가하는 순서로 한 줄에 한 개씩 출력한다. 여러 경우가 존재한다면 첫 번째

www.acmicpc.net

요즘 브루투 포스 알고리즘을 풀면서 생각하는 건데 브루트 포스 문제는 백트래킹 기법을 같이 사용해서 푸는 문제가 많은 것 같다.

재귀함수를 이용하다보니 조건을 만족하면 되돌아 오는 백트래킹을 많이 쓰는 것 같다.

덕분에 함수 다루는 실력이 좀 향상된것 같다. ㅎㅎ (지극히 내 생각이다.....)

 

함수를 2개 사용했다.

첫 번째 함수는 현재 있는 멤버에 새로운 친구가 들어갈 수 있는지 확인해주는 함수이다.

# 새로 들어온 친구가 들어갈 수 있는지 확인하는 함수이다.
# 리스트에 첫 번째 인덱스는 0이 있으니 제외하고 시작하자.
def is_friend(plus_friend, member_list):
    for q in member_list[1:]:
        if plus_friend not in friends[q]:
            return False
    return True

굳이 설명할 필요가 없을 거라고 생각된다.

 

두번째 함수는 재귀함수 + 백트래킹 함수 + 탐색 함수이다.

이 함수가 핵심이다.

# cur_cnt는 현재 만들어진 멤버의 수, cur_list는 그 멤버의 번호이다.
def find_friends(cur_cnt, cur_list):

    # 멤버를 K명 모으면 함수를 종료한다. (재귀함수의 기저사례)
    if cur_cnt == K:
        for q in cur_list[1:]:
            print(q)
        return True

    # 순서대로 들어가기 때문에 cur_list에 있는 번호가 가장 큰 멤버는 -1의 인덱스에 있다.
    # 대신 빈 리스트에 -1을 부르면 에러가 뜨기 때문에 이 함수 호출 전에 반복문으로 0을 넣어주고 시작한다.
    for q in range(cur_list[-1] + 1, N + 1):
        if is_friend(q, cur_list):
            cur_list.append(q)
            if find_friends(cur_cnt + 1, cur_list):
                return True
            cur_list.pop()
    return False

우선 함수가 종료되는 조건은 멤버의 수가 K가 되는 조건이다.

글을 작성하면서 생각해보니 굳이 cur_cnt를 쓰지 않고 len함수를 이용해서 인수를 하나 줄일 수 있었을 것 같다.

 

아래 반복문은 아직 확인하지 않은 값을 is_friend로 확인하면서 가능하다면 해당 멤버를 추가해 다시 함수를 호출하는 부분이다.

백트래킹에서 사용하듯이 만약 해당 값으로 답을 찾을 수 없다면 다 확인해본 후에 pop등을 이용해서 값을 빼주어야 한다.

import sys

K, N, F = map(int, sys.stdin.readline().split())

friends = [[] for i in range(N + 1)]

for i in range(F):
    a, b = map(int, sys.stdin.readline().split())
    friends[a].append(b)
    friends[b].append(a)


# 새로 들어온 친구가 들어갈 수 있는지 확인하는 함수이다.
# 리스트에 첫 번째 인덱스는 0이 있으니 제외하고 시작하자.
def is_friend(plus_friend, member_list):
    for q in member_list[1:]:
        if plus_friend not in friends[q]:
            return False
    return True


# cur_cnt는 현재 만들어진 멤버의 수, cur_list는 그 멤버의 번호이다.
def find_friends(cur_cnt, cur_list):

    # 멤버를 K명 모으면 함수를 종료한다. (재귀함수의 기저사례)
    if cur_cnt == K:
        for q in cur_list[1:]:
            print(q)
        return True

    # 순서대로 들어가기 때문에 cur_list에 있는 번호가 가장 큰 멤버는 -1의 인덱스에 있다.
    # 대신 빈 리스트에 -1을 부르면 에러가 뜨기 때문에 이 함수 호출 전에 반복문으로 0을 넣어주고 시작한다.
    for q in range(cur_list[-1] + 1, N + 1):
        if is_friend(q, cur_list):
            cur_list.append(q)
            if find_friends(cur_cnt + 1, cur_list):
                return True
            cur_list.pop()
    return False


if not find_friends(0, [0]):
    print(-1)

이 문제의 전체코드이다.

import sys

K, N, F = map(int, sys.stdin.readline().split())

friend = {i+1: [] for i in range(N)}

for i in range(F):
    first, second = map(int, sys.stdin.readline().split())
    friend[first].append(second)
    friend[second].append(first)


def judge(plus_friend, members):
    for per in members:
        if per not in friend[plus_friend]:
            return False
    return True


def backtracking(per_cnt, cur_members):
    if per_cnt == K:
        for i in cur_members:
            print(i)
        exit(0)

    for i in range(cur_members[-1] + 1, N + 1):
        if judge(i, cur_members):
            backtracking(per_cnt + 1, cur_members + [i])

for i in range(1, N):
    backtracking(1, [i])

print(-1)

전에 풀었던 코드인데 재귀함수를 빠져나올 방법을 찾지 못해서 그냥 exit로 프로그램을 종료해버렸었다.

물론 이렇게 풀어도 되기는 하지만 재귀함수, 백트래킹을 제대로 사용하기 위해 함수를 빠져 나올 수 있는 방법을 생각하며 풀어야겠다.

'알고리즘 > 브루트포스' 카테고리의 다른 글

백준 4675 셀프 넘버  (1) 2024.01.15
백준 1065 한수  (0) 2024.01.15
게임판 덮기  (0) 2022.09.17
보글 게임  (1) 2022.09.16
조합을 구하는 알고리즘  (0) 2022.09.15
728x90

 

 

algospot.com :: BOGGLE

보글 게임 문제 정보 문제 보글(Boggle) 게임은 그림 (a)와 같은 5x5 크기의 알파벳 격자인 게임판의 한 글자에서 시작해서 펜을 움직이면서 만나는 글자를 그 순서대로 나열하여 만들어지는 영어

algospot.com

 

 

GitHub - Seungkyu-Han/PS_strategy: 알고리즘 분류하는 워크플레이스

알고리즘 분류하는 워크플레이스. Contribute to Seungkyu-Han/PS_strategy development by creating an account on GitHub.

github.com

이 보글게임 문제를 브루트포스, 재귀로 풀 수 있다. (그냥 알고리즘만 구현해보고 채점은 안해봐서 모르겠다... 그냥  참고만)

def hasword(cur_x, cur_y, target_word, visited):  # 해당 위치에 찾는 단어가 있는지 확인하는 함수
    # 범위를 확인하지 않고 넘어오기 때문에 범위 확인을 가장 먼저 해준다.
    if not (0 <= cur_x < 5 and 0 <= cur_y < 5):
        return False

    if len(target_word) == 0:
        return True

    if target_word[0] != board[cur_x][cur_y]:
        return False

    for t in range(8):
        go_x = cur_x + dx[t]
        go_y = cur_y + dy[t]

        if not (0 <= go_x < 5 and 0 <= go_y < 5):
            continue

        if not visited[go_x][go_y]:
            continue

        visited[go_x][go_y] = False
        if hasword(go_x, go_y, target_word[1:], visited):
            return True
        visited[go_x][go_y] = True

    return False

이 알고리즘에서 가장 중요한 함수이다.

이 문제를 해결하기 위해서는

현재 위치(cur_x, cur_y)에 첫 글자가 있는가?

주위의 8칸 중, 그 위치에서 시작해서 단어의 나머지 글자들을 찾을 수 있는가? 를 알아야 한다.

여기서 현재 위치에 첫 글자가 있으면, 주위 칸으로 가서 두번째 문자부터 시작하면 된다.

이 일을 문자가 없어질 때까지 반복한다. (target_len의 길이 == 0이 종료조건)

이렇게 문제를 부분 문제로 나누어서 풀 수 있어야 한다. (솔직히 떠올리기가 어려운 것 같다.)

 

이 알고리즘을 구현하면서 visited를 사용해 한 글자를 두 번 이상 사용하지 못하게 만들었다.

N = int(input('단어의 수를 입력 : '))

words = []

for i in range(N):
    words.append(list(input().strip()))

print('보드를 입력')

board = []

for i in range(5):
    board.append(list(input().strip()))

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


def hasword(cur_x, cur_y, target_word, visited):  # 해당 위치에 찾는 단어가 있는지 확인하는 함수
    # 범위를 확인하지 않고 넘어오기 때문에 범위 확인을 가장 먼저 해준다.
    if not (0 <= cur_x < 5 and 0 <= cur_y < 5):
        return False

    if len(target_word) == 0:
        return True

    if target_word[0] != board[cur_x][cur_y]:
        return False

    for t in range(8):
        go_x = cur_x + dx[t]
        go_y = cur_y + dy[t]

        if not (0 <= go_x < 5 and 0 <= go_y < 5):
            continue

        if not visited[go_x][go_y]:
            continue

        visited[go_x][go_y] = False
        if hasword(go_x, go_y, target_word[1:], visited):
            return True
        visited[go_x][go_y] = True

    return False


def solve(target_word):
    for q in range(5):
        for w in range(5):
            visited_list = [[True] * 5 for i in range(5)]
            if hasword(q, w, target_word, visited_list):
                return True
    return False


for i in range(N):
    if solve(words[i]):
        print(*words[i])

위 함수를 포함한 전체 코드이다.

단어가 많아진다면 트라이를 통해서 더 빠르게 구현할 수 있겠지만 난이도는 많이 높아질 것 같다....

'알고리즘 > 브루트포스' 카테고리의 다른 글

백준 4675 셀프 넘버  (1) 2024.01.15
백준 1065 한수  (0) 2024.01.15
게임판 덮기  (0) 2022.09.17
소풍  (1) 2022.09.16
조합을 구하는 알고리즘  (0) 2022.09.15

+ Recent posts