알고리즘/백준

[백준] 1749 점수따먹기 - JAVA

체제 2023. 6. 20. 16:02

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

 

1749번: 점수따먹기

동주는 항상 혼자 노느라 심심하다. 하지만 혼자 놀기의 고수가 된 동주는 매일매일 게임을 개발하여 혼자놀기의 진수를 우리에게 보여준다. 어느 날 동주는 새로운 게임을 개발하였다. 바로 점

www.acmicpc.net

 

 

알고리즘

  • 누적합/ 부분합 + 완전탐색 
  • 주어진 2차원 배열에서 각 지점까지의 누적합을 구한다.
  • N,M 범위 내에서 시작 지점과 도착 지점의 모든 가능한 경우의 수를 탐색하여 각 부분 행렬의 합을 구한다. 

 

구현 과정

  • sum[][] : 각 지점까지의 누적합 저장한 2차원 배열 
  • findSum(sx, sy, ex, ey) : 시작 지점 (sx, sy) ~ 도착 지점 (ex, ey) 의 부분 구간 합 구하는 메소드

 

1. 입력받은 2차원 배열을 map[][] 에 저장한다. 첫 열/행의 합도 포함시키기 위해 배열의 위쪽/왼쪽을 0으로 채운다. 즉, 입력값 저장은 1번 인덱스 부터 저장.

 

2. 시작점을 배열의 가장 왼쪽 상단으로 하여, 모든 지점까지의 누적합을 sum[][] 에 저장한다. 

(i,j) : sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + map[i][j] ;

 

3. (1~N), (1~M) 내에서 가능한 모든 시작 지점, 도착 지점에 대해 완전 탐색한다. 

 

4. 모든 경우의 시작 지점 ~ 도착 지점에 대해 부분 구간합을 구한다. (findSum 메소드) 

(sx,sy)~(ex,ey) : sum[ex][ey] - sum[sx-1][ey] - sum[ex][sy-1] + sum[sx-1][sy-1];

 

 

💡 누적합, 부분합 모두 '공통으로 포함 되는 구간'을 고려하며 식을 구한다. 

  • 누적합 : (지점 이전의 부분/지점의 값)모든 부분합을 더한 후, 공통으로 포함되어 두번 더한 구간 빼기 
  • 부분합 : 도착 지점까지의 누적합에서 시작 지점 이전의 모든 부분합을 뺀 후, 공통으로 포함되어 두번 뺀 부분 더하기

 


소스 코드

import java.util.*;
import java.io.*;
	
public class Main {
	static int max=Integer.MIN_VALUE;
	static int[][] sum; 
	public static void main(String[] args) throws Exception {
		BufferedReader br= new BufferedReader(new InputStreamReader(System.in)); 
		StringTokenizer st;
		
		st= new StringTokenizer(br.readLine(), " ");
		int N= Integer.parseInt(st.nextToken());
		int M= Integer.parseInt(st.nextToken()); 
		int map[][] = new int[N+1][M+1];
		sum = new int[N+1][M+1]; //누적합 저장
		
		for(int i=1; i<=N; i++) {
			st= new StringTokenizer(br.readLine(), " ");
			for(int j=1; j<=M; j++) {
				map[i][j] = Integer.parseInt(st.nextToken()); 
			}
		}
		
		//누적합 구하기 		
		for(int i=1; i<=N; i++) {
			for(int j=1; j<=M; j++) {
				sum[i][j] = sum[i-1][j] + sum[i][j-1] + map[i][j] - sum[i-1][j-1]; 
			}
		}
		
		
		//시작점, 끝점을 모든 경우의 수 완전 탐색 
		for(int sx= 1; sx<=N; sx++) {
			for (int sy=1; sy<=M; sy++) {
				for(int ex= sx; ex<=N; ex++) {
					for(int ey=sy; ey<=M; ey++) {
						int result= findSum(sx, sy, ex, ey);
						max= Math.max(max, result); 
					}
				}
			}
		}
		
		System.out.println(max);
		
	}//end of main 
	
	//(sx, sy) ~ (ex, ey) 구간합 구하기 
	private static int findSum(int sx, int sy, int ex, int ey) {
		return sum[ex][ey] - sum[sx-1][ey]- sum[ex][sy-1]+ sum[sx-1][sy-1]; 
	}
}//end of class