자료구조&알고리즘/코딩테스트
백준11660/구간합구하기5
밍풀
2022. 9. 17. 06:14
구간합 없이 1차적으로 짠 코드(시간초과)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
package myapp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class doit3 {
public static void main(String[] args) throws IOException{
BufferedReader bu = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(bu.readLine());// 표의크기와 질의갯수 읽어드림
int N= Integer.parseInt(st.nextToken());//표의크기 빼서 넣음
int M=Integer.parseInt(st.nextToken());//질의갯수 빼서 넣음
int table[][]=new int [N][N];//N*N 크기의 표 만듦
for(int i=0;i<N;i++) {
st = new StringTokenizer(bu.readLine());//표 첫째줄에 들어갈 정수들을 받음
for(int j=0;j<N;j++) {
table[i][j]=Integer.parseInt(st.nextToken());//i=1일때 (1,1)(1,2)(1,3)(1,4)에넣고
//i=2일때 (2,1)(2,2)(2,3)(2,4)에 넣는 식
}
}//N*N 테이블에 정수 채워 넣음
int x1,x2,y1,y2;//범위를 결정할 정수 선언
for(int i=0;i<M;i++) {
st = new StringTokenizer(bu.readLine());// (x1,y1)(x2,y2)범위 받음
x1=Integer.parseInt(st.nextToken());
y1=Integer.parseInt(st.nextToken());
x2=Integer.parseInt(st.nextToken());
y2=Integer.parseInt(st.nextToken());//범위 변수에 값 넣어줌
int sum=0;
for(int j=x1;j<=x2;j++) {
for(int k=y1;k<=y2;k++) {
sum= sum+table[j-1][k-1];//(2,1)에서 (4,4)라고 치면
//(2,1)+(2,2)+(2,3)+(2,4)< x1일때, y1~y2까지합
//(3,1)+(3,2)+(3,3)+(3,4)< x1+1일때, y1~y2까지합
//(4,1)+(4,2)+(4,3)+(4,4)< x2일때, y1~y2까지 합
}
}System.out.println(sum);
}
}
}
|
cs |
구간합 도입
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
StringBuilder sb = new StringBuilder();
int n = Integer.parseInt(st.nextToken());
int m = Integer.parseInt(st.nextToken());
int[][] arr = new int[n+1][n+1];
int[][] dp = new int[n+1][n+1];
for (int i = 1; i <= n; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 1; j <= n; j++) {
arr[i][j] = Integer.parseInt(st.nextToken());
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1] + arr[i][j];
}
}
for (int k = 1; k <= m; k++) {
st = new StringTokenizer(br.readLine());
int x1 = Integer.parseInt(st.nextToken());
int y1 = Integer.parseInt(st.nextToken());
int x2 = Integer.parseInt(st.nextToken());
int y2 = Integer.parseInt(st.nextToken());
int ans = dp[x2][y2] - dp[x2][y1-1] - dp[x1-1][y2] + dp[x1-1][y1-1];
sb.append(ans + "\n");
}
System.out.print(sb);
}
}
|
cs |
구간합 dp행렬 채워지는 로직 이해하기
다른건 다 이해했는데
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1] + arr[i][j];
}
}
이부분 코드로 인해 구간합이 다 구해진다는게 이해가 가질 않음(아직 동적계획을 안배운 초짜..)
근데 배열은 만들때 일단 기본적으로 0이 들어간다는 것을 이제야 알게됨.....
걍 변수는 에러뜨는데..;;

그러니 예를들어 2*2 크기의 표인 경우 위 반복문을 풀어 써보면
dp(1,1)=dp(0,1)+dp(1,0)-dp(0,0)+ar(1,1)
dp(1,2)=dp(1,2)+dp(1,1)-dp(0,1)+ar(1,2)
dp(2,1)=dp(1,1)+dp(2,0)-dp(1,0)+ar(2,1)
dp(2,2)는 dp(1,2)+dp(2,1)-dp(1,1)+ar(2,2)
인데
첫번째가 dp(1,1)=dp(0,1)+dp(1,0)-dp(0,0)+ar(1,1) 식에서
ar(1,1)만 값을 아니까 나머지는 0이고 dp(1,1)은 ar(1,1)이 됨
dp(1,2)=dp(1,2)+dp(1,1)-dp(0,1)+ar(1,2)에서
dp(1,1)과 ar(1,2)만 아니까 dp(1,1)+ar(1,2)가 dp(1,2)가 됨
dp(2,1)=dp(1,1)+dp(2,0)-dp(1,0)+ar(2,1)에서
dp(2,1)은 dp(1,1), ar(2,1)만 아니까 dp(1,1)+ar(2,1)이 됨 = > 2*2표 그리면서 확인해 보면 다 들어 맞음
마지막으로
dp(2,2)는 dp(1,2)+dp(2,1)-dp(1,1)+ar(2,2) 이건 다 값을 아니까 다 더해서 구해짐
점화식을 알때 초항을 알면 다음건 구할 수 있는 식....