행렬의 거듭 제곱 구하기(난이도: 하)

2022. 9. 2. 10:24·알고리즘 (with JAVA)/분할 정복 알고리즘

1. 문제 설명

(1) 크기가 N*N인 행렬 A가 주어진다. 이때,  A^B를 구하는 프로그램을 작성한다.

 

 

 

 

2. 입출력 조건 및 예제

입력 조건

(1) 2 <= N <= 5, 1 <= B <= 100,000,000,000으로 제한한다.

 

출력 조건

(1) 원소가 크면 문제가 발생할 수 있으므로, A^B의 원소를 1000으로 나눈 나머지를 출력한다.

 

 

입력 예제

3

2 5                  <-- 행렬 크기와 지수

1 2

3 4

3 3                  <-- 행렬 크기와 지수

1 2 3

4 5 6

7 8 9

5 10                 <-- 행렬 크기와 지수

1 0 0 0 1

1 0 0 0 1

1 0 0 0 1

1 0 0 0 1

1 0 0 0 1

 

출력 예제

69 558

337 406

 

468 576 684

62 305 548

656 34 412

 

512 0 0 0 512

512 0 0 0 512

512 0 0 0 512

512 0 0 0 512

512 0 0 0 512

 

 

 

 

3. 제약 조건

X

 

 

 

 

4. 가정법

X

 

 

 

 

5. 기저 사례

(1) 지수가 1인 상태

 

 

 

 

6. 코드

public class MatrixPow {
    // 홀수를 위한 복사 행렬과 행령의 크기 
    private static int[][] Matrix;
    private static int N;

    // 출력을 위한 변수
    private static StringBuilder sb = new StringBuilder();

    public static void main(String[] args) throws IOException {
        BufferedReader sc = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;

        int C = Integer.parseInt(sc.readLine());
        for(int i=0; i<C; i++) {
            st = new StringTokenizer(sc.readLine());
            N = Integer.parseInt(st.nextToken());
            int B = Integer.parseInt(st.nextToken());
            int[][] A = new int[N][N];

            // 행렬에 값을 넣는 과정
            for(int y=0; y<N; y++) {
                st = new StringTokenizer(sc.readLine());
                for(int x=0; x<N; x++) {
                    A[y][x]= Integer.parseInt(st.nextToken());
                }
            }
            // 홀수가 나오면 사용하는 행렬
            // 예) 2^7 = (2^6)*MATRIX
            Matrix = A;

            // 주요 메서드 실행과 동시에 값 저장
            writeArr(solve(A, B));
        }
        System.out.println(sb);
    }

    // 거듭제곱 행렬을 수행하기 위해
    // 분할 정복하는 주요 메서드
    private static int[][] solve(int[][] a, int b) {

        // 기저사례(1): 지수가 1이라면 바로 행렬 리턴
        if(b==1) return a;

        // 분할 시작
        int[][] ret = solve(a, b/2);

        // 행렬 곱 수행
        ret = multiplyMatrix(ret, ret);

        // 홀수라면 아까 위해서 말했던 Matrix 곱
        if(b%2==1) ret = multiplyMatrix(ret, Matrix);

        return ret;
    }

    // a와 b 행렬을 서로 곱셈을 수행하는 메서드
    private static int[][] multiplyMatrix(int[][] a, int[][] b){
        int[][] ret = new int[N][N];

        for(int i=0; i<N; i++){
            for(int j=0; j<N; j++) {
                for(int k=0; k<N; k++) {
                    ret[i][j]+=a[i][k]*b[k][j];
                }
            }
        }
        return ret;
    }

    // 거듭제곱의 결과를 %1000으로 수행하여 출력하는 메서드
    private static void writeArr(int[][] a) {
        for(int i=0; i<N; i++) {
            for(int j=0; j<N; j++) {
                sb.append((a[i][j]%1000) +" ");
            }
            sb.append("\n");
        }
        sb.append("\n");
    }
}

 

( 여기서 왜 홀수를 절반으로 안 나누고 짝수를 구한 후 홀수를 곱하는 지 의문이 들 수 있다. )

( 그 이유는 아래의 그림처럼 만약 홀수까지 나누게 되면, 결국 홀수의 부분문제와 짝수의 부분문제에서

호출의 발생이 중복되는 경우가 많기 때문이다. )

 

( 이렇게 되면 지수 크기가 커질수록 선형적으로 증가하게 된다. ) 

 

( 그러나, 아래의 그림처럼 짝수만 나눠준다면 호출의 발생이 중복되지 않으며, O(lgN)개 만큼 호출하게 된다. )

저작자표시 (새창열림)

'알고리즘 (with JAVA) > 분할 정복 알고리즘' 카테고리의 다른 글

팬미팅 (난이도 - 상)  (0) 2022.09.14
카라츠바의 빠른 곱셈 알고리즘(2) - O(N^lg3)  (1) 2022.09.14
카라츠바의 빠른 곱셈 알고리즘(1) - O(N^2)  (0) 2022.09.13
울타리 잘라내기(난이도 - 중)  (0) 2022.09.08
쿼드 트리 뒤집기(난이도 - 하)  (0) 2022.09.06
'알고리즘 (with JAVA)/분할 정복 알고리즘' 카테고리의 다른 글
  • 카라츠바의 빠른 곱셈 알고리즘(2) - O(N^lg3)
  • 카라츠바의 빠른 곱셈 알고리즘(1) - O(N^2)
  • 울타리 잘라내기(난이도 - 중)
  • 쿼드 트리 뒤집기(난이도 - 하)
백_곰
백_곰
  • 백_곰
    친절한 코딩
    백_곰
  • 전체
    오늘
    어제
    • 분류 전체보기
      • 알고리즘 (with JAVA)
        • 기본 알고리즘
        • 완전 탐색
        • 분할 정복 알고리즘
        • 동적 계획법
        • 탐욕법
        • 코딩 테스트 기출 문제
        • 코드트리 조별과제
      • 백준 (with JAVA)
        • 완전 탐색
        • 분할 정복
        • 그 외
      • 자바
        • 개발 환경 구축하기
        • 팁
        • 기본적인 개념
        • 컬렉션 프레임워크
        • 프로세스와 쓰레드
        • 지네릭스
        • 람다식
        • 스트림
        • 입출력 IO
        • 네트워킹
        • 열거형(enums)
        • java.lang 패키지
        • java.time 패키지
        • 유용한 클래스들
        • 형식화 클래스들
      • 안드로이드 with 자바
        • 응용 문제들
        • 자잘한 문제들
        • 오류 보고서
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

      스트림
      자바 개념
      serializable
      소켓 프로그래밍
      file
      코드트리
      제자리 정렬
      java.lang패키지
      outputstream
      snail
      코딩트리조별과제
      유용한 클래스
      ServerSocket
      안드로이드 스튜디오
      InputStream
      알고스팟
      코딩테스트
      중간연산
      TCP 소켓 프로그래밍
      안정 정렬
      람다식
      다형성
      Collections Framework
      불안정 정렬
      Arrays
      map()
      java.time 패키지
      문자 기반 스트림
      역직렬화
      선택 정렬
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.3
    백_곰
    행렬의 거듭 제곱 구하기(난이도: 하)
    상단으로

    티스토리툴바