어제의 나보다 성장한 오늘의 나

[백준][BOJ-10830][자바] 행렬 제곱 본문

알고리즘/백준(BOJ)

[백준][BOJ-10830][자바] 행렬 제곱

NineOne 2021. 4. 6. 00:22

www.acmicpc.net/problem/10830

 

10830번: 행렬 제곱

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

www.acmicpc.net

import java.io.*;
import java.util.*;

public class Main {
	static HashMap<Long, int[][]> hm = new HashMap<>();
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		int N = Integer.parseInt(st.nextToken());
		long B = Long.parseLong(st.nextToken());
		int[][] matrix = new int[N][N];
		
		for(int i=0; i<N; i++) {
			st = new StringTokenizer(br.readLine());
			for(int j=0; j<N; j++) {
				matrix[i][j] = Integer.parseInt(st.nextToken());
			}
		}
		
		// 처음부터 1000이 넘게 들어오는 경우
		matrix = matrixMod(matrix);
		
		// A^1 과 A^2 저장
		hm.put((long) 1, matrix);
		multiplyMatrix(matrix, matrix,2);
		
		divideConquer(B);
		
		int[][] result = hm.get(B);
		
		for(int i=0; i<N; i++) {
			for(int j=0; j<N; j++) {
				System.out.print(result[i][j]+" ");
			}
			System.out.println();
		}
	}
	
	public static void divideConquer(long cnt){
		if(hm.containsKey(cnt)) return;
		
		long first = 0;
		long second = cnt/2;
		
		if(cnt %2 == 0) first = cnt/2;
		else first = (cnt/2)+1;
		
		divideConquer(first);
		divideConquer(second);
		
		multiplyMatrix(hm.get(first), hm.get(second), cnt);
	}
	
	public static int[][] multiplyMatrix(int[][] a, int[][] b, long cnt){
		int[][] temp = new int[a.length][a.length];
		
        for(int i=0; i<a.length;i++){
            for(int j=0; j<b[0].length;j++){
                for(int k=0; k<a[0].length;k++){
                	temp[i][j] += a[i][k]*b[k][j];
                }
                 
            }
        }
        
        temp = matrixMod(temp);
        hm.put(cnt, temp);
        return temp;
        
	}
	
	public static int[][] matrixMod(int[][] matrix){
		for(int i=0; i<matrix.length; i++) {
			for(int j=0; j<matrix[0].length; j++) {
				matrix[i][j] %= 1000;
			}
		}
		return matrix;
	}
}

정리

  • 처음부터 행렬A에 1000이 넘는 값이 들어올 수 있어서 처리를 해줘야 한다. ( 80프로에서 틀린다... )
  • A^1과 A^2에 대한 값을 HashMap에 저장한다.
  • 재귀를 통해 HashMap에 값이 있다면 더 이상 분할하지 않는다.
  • multiplyMatrix()를 통해 곱하고 HashMap에 저장한다.
  • 곱이 일어나는 매 순간마다 %1000을 해줘야한다.
Comments