백준 11660 [자바] java 구간 합 구하기 5
문제 링크: https://www.acmicpc.net/problem/11660
▶문제
N×N개의 수가 N×N 크기의 표에 채워져 있다. (x1, y1)부터 (x2, y2)까지 합을 구하는 프로그램을 작성하시오. (x, y)는 x행 y열을 의미한다.
예를 들어, N = 4이고, 표가 아래와 같이 채워져 있는 경우를 살펴보자.
1 | 2 | 3 | 4 |
2 | 3 | 4 | 5 |
3 | 4 | 5 | 6 |
4 | 5 | 6 | 7 |
여기서 (2, 2)부터 (3, 4)까지 합을 구하면 3+4+5+4+5+6 = 27이고, (4, 4)부터 (4, 4)까지 합을 구하면 7이다.
표에 채워져 있는 수와 합을 구하는 연산이 주어졌을 때, 이를 처리하는 프로그램을 작성하시오.
▶입력
첫째 줄에 표의 크기 N과 합을 구해야 하는 횟수 M이 주어진다. (1 ≤ N ≤ 1024, 1 ≤ M ≤ 100,000) 둘째 줄부터 N개의 줄에는 표에 채워져 있는 수가 1행부터 차례대로 주어진다. 다음 M개의 줄에는 네 개의 정수 x1, y1, x2, y2 가 주어지며, (x1, y1)부터 (x2, y2)의 합을 구해 출력해야 한다. 표에 채워져 있는 수는 1,000보다 작거나 같은 자연수이다. (x1 ≤ x2, y1 ≤ y2)
▶출력
총 M 줄에 걸쳐 (x1, y1)부터 (x2, y2)까지 합을 구해 출력한다.
▶해설
(x1,y1) ~ (x2, y2)까지 모든 합을 들어올 때마다 구한다면 시간 초과가 뜰 것입니다.
(1,1) ~ (a,b) 임의의 점까지 모든 합을 구합니다.
dp에 값(모든 합)을 채워줍니다.
private static void makeDpMap() {
for(int i=1; i<=n; i++){ // (1,i),(i,1) 은 값을 채워줍니다.
dp[1][i]=map[1][i]+dp[1][i-1];
dp[i][1] = map[i][1]+dp[i-1][1];
}
for(int i=2; i<=n; i++){ // 중복되는 곳을 빼줍니다.
for(int j=2; j<=n; j++){
dp[i][j]= dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1] + map[i][j];
}
}
}
1 | 2 | 3 |
4 | 5 | 6 |
7 | 8 | 9 |
(1,1) ~ (1,1) = 1 -> (1,1)
(1,1) ~ (1,2) = 3 -> (1,1) + (1,2)
(1,1) ~ (2,1) = 5 -> (1,1) + (2,1)
그렇다면 (1,1) ~ (2,2) = (2,2) + (1,1) ~ (1,2) + (1,1) ~ (2,1) - (1,1) ~ (1,1)로 구성됩니다.
따라서 사각형을 중점으로 구한 합에서 속하지 않는 곳을 빼고 중복되는 곳을 다시 더해주면 됩니다.
점화식을 구할 수 있습니다.
dp[i][j]-(dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1])
public class Main {
static int n, m;
static int [][] dp, map;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] s = br.readLine().split(" ");
n = Integer.parseInt(s[0]);
m = Integer.parseInt(s[1]);
map = new int[n + 1][n + 1];
dp = new int[n+1][n+1];
for (int i = 1; i <= n; i++) {
String[] s1 = br.readLine().split(" ");
for (int j = 1; j <= n; j++) {
map[i][j] = Integer.parseInt(s1[j - 1]);
}
}
int result = 0;
int xStart;
int yStart;
int xEnd;
int yEnd;
makeDpMap();
for (int i = 0; i < m; i++) {
String[] s1 = br.readLine().split(" ");
yStart = Integer.parseInt(s1[0]);
xStart = Integer.parseInt(s1[1]);
yEnd = Integer.parseInt(s1[2]);
xEnd = Integer.parseInt(s1[3]);
result = solve(yStart,xStart,yEnd,xEnd);
System.out.println(result);
}
}
private static void makeDpMap() { // 합을 구하는 부분
for(int i=1; i<=n; i++){
dp[1][i]=map[1][i]+dp[1][i-1];
dp[i][1] = map[i][1]+dp[i-1][1];
}
for(int i=2; i<=n; i++){
for(int j=2; j<=n; j++){
dp[i][j]= dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1] + map[i][j];
}
}
}
private static int solve(int yStart, int xStart, int yEnd, int xEnd){
return dp[yEnd][xEnd]-(dp[yStart-1][xEnd]+dp[yEnd][xStart-1]-dp[yStart-1][xStart-1]);
}
}
'Alogorithm > DP' 카테고리의 다른 글
백준 12865 [자바] java 평범한 배낭 (0) | 2022.03.01 |
---|---|
백준 2293 [자바] java 동전 1 (0) | 2022.02.28 |
백준 2156 [자바] java 포도주 시식 (0) | 2022.02.22 |
백준 11053[자바] java 가장 긴 증가하는 부분 수열 (0) | 2022.02.19 |
백준 1106 [자바] java 호텔 (0) | 2022.01.11 |
댓글
이 글 공유하기
다른 글
-
백준 12865 [자바] java 평범한 배낭
백준 12865 [자바] java 평범한 배낭
2022.03.01 -
백준 2293 [자바] java 동전 1
백준 2293 [자바] java 동전 1
2022.02.28 -
백준 2156 [자바] java 포도주 시식
백준 2156 [자바] java 포도주 시식
2022.02.22 -
백준 11053[자바] java 가장 긴 증가하는 부분 수열
백준 11053[자바] java 가장 긴 증가하는 부분 수열
2022.02.19