차곡차곡

[BOJ/Java] 백준 17406번 - 배열 돌리기 4 본문

CS/Algorithm

[BOJ/Java] 백준 17406번 - 배열 돌리기 4

sohy 2023. 8. 11. 10:30

백준 #117406 배열 돌리기 4

 

17406번: 배열 돌리기 4

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

www.acmicpc.net

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.StringTokenizer;

public class Main {
	
	static int N, M, K;
	static int[][] map;
	static int[][] newMap;
	static int[][] com;
	static int[] comPer;
	static int min = Integer.MAX_VALUE;
	static int [] dx = {0, 1, 0, -1};
	static int [] dy = {1, 0, -1, 0};

	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());  // 회전 연산 개수
		map = new int[N][M];  // 배열
		com = new int[K][3];  // 회전 연산
		
		for (int i = 0; i < N; i++) {
			st = new StringTokenizer(br.readLine());
			for (int j = 0; j < M; j++) {
				map[i][j] = Integer.parseInt(st.nextToken()); 
			}
		}
		
		for (int i = 0; i < K; i++) {
			st = new StringTokenizer(br.readLine());
			for (int j = 0; j < 3; j++) {
				com[i][j] = Integer.parseInt(st.nextToken()); 
			}
		}

		comPer = new int[K];  // 회전 연산 순열
		
		
		// 회전 연산 순열 구하기
		makeCom(0, 0);
		System.out.println(min);
		
	}
	
	public static void makeCom(int cnt, int flag) {
		if (cnt == K) {
			// 회전된 배열 저장할 새 배열 
			newMap = new int[N][M];
			for (int i = 0; i < N; i++) {
				for (int j = 0; j < M; j++) {
					newMap[i][j] = map[i][j];
				}
			}
			
			for (int i = 0; i < K; i++) {
				turn(com[comPer[i]][0]-1, com[comPer[i]][1]-1, com[comPer[i]][2]);
			}
			findMin();
			return;
		}
		
		for (int i = 0; i < K; i++) {
			if ((flag & 1<<i) != 0) continue;
			comPer[cnt] = i;
			makeCom(cnt+1, flag | 1<<i);
		}
	}
	
	// 회전 연산
	public static void turn(int r, int c, int s) {
		
		for (int i = 1; i < s+1; i++) {
			// 일차원 배열에 값 담기
			int len = (int)(Math.pow(1 + i * 2, 2) - Math.pow(1 + (i-1) * 2, 2));
			int[] line = new int[len];
			int x = r-i;
			int y = c-i-1;
			int dirNum = 0;
			for (int j = 0; j < len; j++) {
				int nx = x + dx[dirNum];
				int ny = y + dy[dirNum];
				if (!(r-i <= nx && nx <= r+i && c-i <= ny && ny <= c+i)) {
					dirNum = (dirNum + 1) % 4;
				}
				x = x + dx[dirNum];
				y = y + dy[dirNum];
				line[j] = newMap[x][y];
			}
			
			// 시계 방향으로 돌려서 넣기
			x = r-i;
			y = c-i;
			dirNum = 0;
			for (int j = 0; j < len; j++) {
				int nx = x + dx[dirNum];
				int ny = y + dy[dirNum];
				if (!(r-i <= nx && nx <= r+i && c-i <= ny && ny <= c+i)) {
					dirNum = (dirNum + 1) % 4;
				}
				x = x + dx[dirNum];
				y = y + dy[dirNum];
				newMap[x][y] = line[j];
			}
		}
		
		
	}
	
	
	// 각 행 최솟값 반환
	public static void findMin() {
		for (int i = 0; i < N; i++) {
			int sum = 0;
			for (int j = 0; j < M; j++) {
				sum += newMap[i][j];
			}
			min = Math.min(min, sum);
		}
		return;
	
		
	} 
}  // end of class
  • 회전 연산 순서의 순열을 구한다. (모든 경우의 수를 구하는 것)
  • 각 순서에 맞춰 회전 연산을 진행한다.
    • 돌려야 하는 값들을 일차원 배열에 넣어준 후, 맨왼쪽 위 두 번째 칸부터 시작해서 일차원 배열에 넣은 값들로 채워준다.
  • 회전 연산이 끝나면 각 행의 합을 구해 최솟값을 갱신해준다.
  • 순열 값들 반복

 


 

범위로 준 부분을 다 시계 방향으로 돌리고 행 min 값을 찾아야 되는데, 안쪽 돌리고 찾고, 바깥쪽 돌리고 찾고 이래서 계속 값이 틀리고 있었다. 후

Comments