1 분 소요

문제

정수 삼각형의 한 모습이다.

맨 위층 7부터 시작해서 아래에 있는 수 중 하나를 선택하여 아래층으로 내려올 때, 이제까지 선택된 수의 합이 최대가 되는 경로를 구하는 프로그램을 작성하라. 아래층에 있는 수는 현재 층에서 선택된 수의 대각선 왼쪽 또는 대각선 오른쪽에 있는 것 중에서만 선택할 수 있다.


핵심 아이디어

DP

각 행의 특정 열까지의 최대합은 이전 행의 왼쪽, 오른쪽 열까지의 최대합+ 그 행의 값 까지이다

따라서, 점화식은 다음과 같다.

dp[i][j] = Math.max(dp[i-1][j-1] + tri[i][j] , dp[i-1][j] + tri[i][j])


Points
  • ‘삼각형‘을 코드로 구현하는 것, 즉 배열의 index를 어떻게 처리해줄지가 관건이다

    문제가 삼각형이라해서 꼭 dp. index도 삼각형으로 해줄필요없다. i 행 첫번째 index부터 채워주되, 이전 행의 열값을 비교할 때 왼쪽위를 j-1로, 오른쪽 위를 j 로 가져와 비교함으로써 삼각형을 구현한다.

  • Out Of Range 방지

    열을 채워줄 때 0번부터 채워주면 왼쪽에서 내려올 때 그 열값이 0 이전의 값인지 체크하는 코드가 추가로 필요하다. 이를 방지하기 위해 0행, 0열을 빈배열로 만들어주고 실제 값은 1행, 1열부터 채운다.

    이렇게 하면 왼쪽위의 값을 참조할 때 빈 요소(0)을 참조하므로 최댓값 비교에서 자연스럽게 제외된다.

    이렇게 쿠션을 만들어주는 트릭은 자주 사용되므로 활용하자


코드
import java.util.* ;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in) ; 
        int n = sc.nextInt() ; 
        int[][] tri = new int[n+1][n+1] ; 
        
        // input 
        for(int i = 1 ; i <= n ; i++){
            tri[i][0] = 0 ; 
            for(int j = 1 ; j <= i ; j++){
                tri[i][j] = sc.nextInt() ; 
            }
        }
        
				// dp 
				for(int i = 2 ; i <= n ; i++){
            for(int j = 1 ; j <= i ; j++){
                tri[i][j] = Math.max(tri[i-1][j-1]+tri[i][j] 
                                     , tri[i-1][j]+tri[i][j]) ; 
            }    
        }
        
        // print answer
        int answer = 0 ; 
        for(int i = 1 ; i <= n ; i++){
            answer = Math.max(answer, tri[n][i]) ; 
        }
        System.out.println(answer); 
    }
}


댓글남기기