happy318
팽도리블로그
happy318
전체 방문자
오늘
어제
  • 전체글 (252)
    • 공부 (5)
      • Algorithm 정리 (0)
      • 논문리뷰 (1)
      • C++ (2)
      • Python (2)
      • Java (0)
      • Back-end (0)
      • Front-end (0)
      • Embedded (0)
    • 코딩테스트 (218)
      • Python 문제풀이 (100)
      • C++ 문제풀이 (108)
      • Python template (9)
      • C++ template (1)
    • 일상 (20)
      • 맛집 (13)
      • 쇼핑 (5)
      • 아무 일상 (2)
    • 게임 (9)
      • 메이플스토리 (9)

최근 글

인기 글

hELLO · Designed By 정상우.
happy318

팽도리블로그

코딩테스트/Python 문제풀이

[백준] 행렬 제곱

2022. 7. 8. 14:35

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

 

10830번: 행렬 제곱

크기가 N*N인 행렬 A가 주어진다. 이때, A의 B제곱을 구하는 프로그램을 작성하시오. 수가 매우 커질 수 있으니, A^B의 각 원소를 1,000으로 나눈 나머지를 출력한다.

www.acmicpc.net

분할정복을 이용하는 문제입니다.

 

우선 문제부터 간단하게 요약하면, 

N*N의 행렬과 이것을 몇제곱 할지가 주어지면, 행렬을 해당하는 만큼 제곱한 결과를 return해야 합니다. 

 

<Solution>

거듭제곱에 대한 이야기는 이전 여러 문제들에서 분할정복 방식으로 해결한 적이 있습니다. 

https://life318.tistory.com/61

 

[백준] 곱셈

https://www.acmicpc.net/problem/1629 1629번: 곱셈 첫째 줄에 A, B, C가 빈 칸을 사이에 두고 순서대로 주어진다. A, B, C는 모두 2,147,483,647 이하의 자연수이다. www.acmicpc.net 분할정복을 이용하는 문제..

life318.tistory.com

https://life318.tistory.com/22

 

[백준] 이항 계수 3(페르마 소정리, modular inverse, 분할정복)

https://www.acmicpc.net/problem/11401 11401번: 이항 계수 3 자연수 \(N\)과 정수 \(K\)가 주어졌을 때 이항 계수 \(\binom{N}{K}\)를 1,000,000,007로 나눈 나머지를 구하는 프로그램을 작성하시오. www.acmicp..

life318.tistory.com

 

간단하게 자연수에 대해 생각해봅시다. 만약 2^100을 구한다고 생각하면 

 

2^100 -> 2^50 * 2^50

2^50 -> 2^25 * 2^25

2^25 -> 2^12 * 2^12 *2

.....

 

이러한 방식으로 지수 부분을 2로 나눈 값을 먼저 구하고 이것을 제곱하는 방식으로 문제를 해결할 수 있습니다.

 

행렬 또한 마찬가지로 똑같은 방식으로 해결이 가능합니다. 

이를 위해 행렬을 곱하는 함수를 만들었고 기존에 만들어 두었던 분할정복을 이용한 거듭제곱 함수를 변형 시켜서 문제를 해결하였습니다. 

https://life318.tistory.com/62

 

거듭제곱 분할정복

# 11^12를 구해야하면 # exp(11,12)를 하면 됨 # 실제 사용시 recursion함수이기에 recursion error와 # 나머지를 return 하라는 문제조건 등에 유의하기 # ps: 나머지를 return 해야할시 return이 붙은 모든곳에..

life318.tistory.com

 

행렬을 곱하는 것은 numpy같은 라이브러리를 사용할 수 없으므로 map과 zip을 적절히 활용하면 크게 어렵지 않게 구현할 수 있습니다. 

 

실제 구현은 아래와 같습니다.

import sys

N , B = list(map(int,sys.stdin.readline().rstrip().split()))

def multiple_matrix(A,B):
    # find dimension (row -> m, column -> n)
    m_A = len(A)
    n_A = len(A[0])
    m_B = len(B)
    n_B = len(B[0])
    assert(m_A == n_B and n_A == m_B)
    # return matrix
    return_matrix = [[] for _ in range(m_A)]
    tmp = list(zip(*B))

    for i in range(m_A):
        for j in range(n_B):
            return_matrix[i].append(sum(map(lambda x : x[0] * x[1], zip(A[i], tmp[j]))) % 1000)
    return return_matrix

def exp(base, expo):
    if expo == 1:
        n_base = []
        for row in base:
            n_base.append(list(map(lambda x: x%1000, row)))
        return n_base
    a = exp(base, expo//2)
    b = expo%2
    
    if b == 0: 
        return multiple_matrix(a,a)
    else: # b ==1
        return multiple_matrix(multiple_matrix(a,a),base)

# build matrix
matrix = []
for _ in range(N):
    matrix.append(list(map(int, sys.stdin.readline().rstrip().split())))

return_matrix = exp(matrix, B)

for row in return_matrix:
    n_row = list(map(str, row))
    print(' '.join(n_row))

 

반응형

'코딩테스트 > Python 문제풀이' 카테고리의 다른 글

[백준] 가장 긴 바이토닉 부분 수열  (0) 2022.07.09
[백준] 가장 긴 증가하는 부분 수열  (0) 2022.07.08
[백준] N-Queen  (0) 2022.07.08
[백준] 스티커  (0) 2022.07.07
[백준] 이진 검색 트리  (0) 2022.07.07
    '코딩테스트/Python 문제풀이' 카테고리의 다른 글
    • [백준] 가장 긴 바이토닉 부분 수열
    • [백준] 가장 긴 증가하는 부분 수열
    • [백준] N-Queen
    • [백준] 스티커
    happy318
    happy318

    티스토리툴바