카테고리 없음

[17406] 배열 돌리기4 in Java

여니's 2022. 8. 11. 09:32

 

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

 

17406번: 배열 돌리기 4

크기가 N×M 크기인 배열 A가 있을때, 배열 A의 값은 각 행에 있는 모든 수의 합 중 최솟값을 의미한다. 배열 A가 아래와 같은 경우 1행의 합은 6, 2행의 합은 4, 3행의 합은 15이다. 따라서, 배열 A의

www.acmicpc.net

 


문제 요약

배열 크기 : N X M
1 ≤ r-s < r < r+s ≤ N
1 ≤ c-s < c < c+s ≤ M
가장 왼쪽 윗칸 (r-s,c-s), 가장 오른쪽 아랫 칸 (r+s,c+s)인 정사각형을 시계방향으로 한 칸씩 돌린다.

배열 A의 값 : 각 행의 모든 수의 합 중 최솟값
우리가 구해야하는 것 : 배열 A값 중에서 최솟값


 

 

문제 접근 방식

1. 순열을 통해 회전 연산의 순서를 정한다.

2. rotate 함수를 통해 회전 연산을 진행한다.

3. 회전연산을 모두 완료한 후 findMin() 함수를 통해 배열 A의 최솟값을 구한다.

4. tempArray에 원본 배열 array를 넣어 다시 초기화한다.

 

tempArray는 회전 작업 배열이고

array는 원본 배열이다.

 

회전 연산을 처음 진행할 때에는 원본배열로 시작해야 하기 때문에

원본 배열은 변경되면 안된다.

그래서 임시 배열 tempArray를 가지고

회전 연산을 진행해야 한다.

 

 


 

시행 착오

- rotate 함수 내에서 upX, upY, downX, downY의 값을 초기화해주는 과정이

잘못 되어있는 걸 뒤늦게 발견했다.

while문을 돌때마다 해당 변수에 +1씩 추가되도록 해야한다.

 

 

 

 

내가 전에 작성했던 코드는 아래와 같다.

틀린 코드

 

 

1번째에는 0이 더해진다.

2번째에는 1이 더해지고

따라서 k가 1이하일땐 문제가 일어나지 않는다

그래서 문제 사이트에서 주어진 테케가 올바르게 나왔나보다..

 

쨋든 k가 2 이상일때부터 오류가 발생하기 시작한다.

for문을 돌릴때마다 +1씩 증가하도록 설계를 해야하는데

위에 작성한 코드는 이에 해당하지 않는다.

 

(예시)

upX를 3이라고 가정한다.

 

k=0일때

upX = upX + 0 = upX

3 = 3+0 = 3

upX = 3

 

k=1일때

upX = upX + 1 = 3+1=4

upX=4

 

이제 여기서부터 문제가 발생한다.

k=2일때

upX = upX + 2 = 4 + 2 = 6

우리가 원하는 값은 upX + 1 = 4+1 = 5인데

6이라는 수가 나왔다...

 

따라서 이 코드는 틀린 코드였던 것이다!

 

 

따라서 이를 수정해주려면

 upX, upY . .. 의 변수 초기화를 for문 내에서 진행해주어야한다.

 

 

- (r,c,s)를 한꺼번에 저장하는 과정에서 어려움을 겪었다.

파이썬이었으면 튜플형식으로 묶어서 배열에 넣었을텐데

자바에서는 그게 되지 않았다..

 

그래서 고민한 결과

rotateArray라는 2차원 배열을 만들었다.

new int[K][3]

K행, 3열 크기의 배열을 만들었다.

rotateArray[0][0] = r 

rotateArray[0][1] = c

rotateArray[0][2] = s

 

 

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package day_0810;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
 
public class study17406 {
    static int n; // 행
    static int m; // 열
    static int K; // 연산의 개수
    static int[][] array; // 원본 배열
    static int[][] tempArray; // 작업 배열
    static int[][] rotateArray; // r,c,s 보관 배열
    static boolean[] visited; // 방문 체크 배열
    static int[] selected; // 순열로 뽑은 순서 담아놓은 배열
    static int findMinAnswer=Integer.MAX_VALUE; // 배열값
 
    public static void findMin() {
        for(int i=1; i<=n; i++) {
            int temp=0;
            for(int j=1; j<=m; j++) {
                temp+=tempArray[i][j];
            }
            if (findMinAnswer>temp) {
                findMinAnswer=temp;
            }
        }
    }
    
    public static void permu(int cnt) {
        if (cnt==K) {
            for(int i=0; i<K; i++) {
                int curIdx=selected[i];
                int r=rotateArray[curIdx][0];
                int c=rotateArray[curIdx][1];
                int s=rotateArray[curIdx][2];
                rotate(r,c,s); // r,c,s 값 넘겨서 회전 진행
            }
            findMin(); // 배열 A의 최솟값 구하기
            // tempArray 초기화
            for(int i=1; i<=n; i++) {
                for(int j=1; j<=m; j++) {
                    tempArray[i][j]=array[i][j];
                }
            }
            return;
        }
        for (int idx = 0; idx < K; idx++) {
            if (visited[idx]) {
                continue;
            }
            visited[idx]=true;
            selected[cnt]=idx;
            permu(cnt+1);
            visited[idx]=false;
            selected[cnt]=0;
        }
    }
    
    public static void rotate(int r,int c, int s) { 
        int[][] newArray = new int[n+1][m+1];
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=m; j++) {
                newArray[i][j]=tempArray[i][j];
            }
        }
        int upX; int upY; int downX; int downY;
        int depth=0;
        while(true) {
            upX=r-s+depth; // 가장 왼쪽 윗 칸 x값
            upY=c-s+depth; // 가장 왼쪽 윗 칸 y값
            downX=r+s-depth; // 가장 오른쪽 아랫 칸 x값
            downY=c+s-depth; // 가장 오른쪽 아랫 칸 y값
            
            if(upX>=downX || upY>=downY) break;
            
            // 시계방향
            // 1. 맨 윗줄 (오른쪽으로 1칸씩 이동)
            for(int i=upY; i<downY; i++) {
                newArray[upX][i+1]=tempArray[upX][i];
            }
            // 2. 맨 오른쪽 줄 (아랫쪽으로 1칸씩 이동)
            for(int i=upX; i<downX; i++) {
                newArray[i+1][downY]=tempArray[i][downY];
            }
            // 3. 맨 아랫 줄 (왼쪽으로 1칸씩 이동)
            for(int i=upY; i<downY; i++) {
                newArray[downX][i]=tempArray[downX][i+1];
            }
            // 4. 맨 왼쪽 줄 (윗쪽으로 1칸씩 이동)
            for(int i=upX; i<downX; i++) {
                newArray[i][upY]=tempArray[i+1][upY];
            }
            depth++;
        }
        // 변경된 배열 tempArray에 깊은 복사
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=m; j++) {
                tempArray[i][j]=newArray[i][j];
            }
        }
    }
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        n=Integer.parseInt(st.nextToken()); // 행의 크기
        m=Integer.parseInt(st.nextToken()); // 열의 크기
        K=Integer.parseInt(st.nextToken()); // 회전 연산의 개수
        rotateArray=new int[K][3]; // r,c,s 담고 있는 2차원 배열
        selected=new int[K]; // 순열에서 사용하는 배열
        visited=new boolean[K]; // 순열에서 사용하는 배열
        
        // 배열 입력 받기
        array=new int[n+1][m+1]; 
        tempArray=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++) {
                array[i][j]=Integer.parseInt(st.nextToken());
                tempArray[i][j]=array[i][j];
            }
        }
        // 회전 연산
        for(int k=0; k<K; k++) {
            st=new StringTokenizer(br.readLine());
            int r=Integer.parseInt(st.nextToken()); // 행 
            int c=Integer.parseInt(st.nextToken()); // 열
            int s=Integer.parseInt(st.nextToken()); 
            // 회전 연산을 수행할 공간 범위 잡기 
            rotateArray[k][0]=r;
            rotateArray[k][1]=c;
            rotateArray[k][2]=s;
        }
        permu(0);
        
        // 최종값 출력하기
        System.out.print(findMinAnswer);
    }
}
cs