just do it

백준11660/구간합구하기5 본문

자료구조&알고리즘/코딩테스트

백준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) 이건 다 값을 아니까 다 더해서 구해짐

 

점화식을 알때 초항을 알면 다음건 구할 수 있는 식.... 

 

점화식의 로직이해