비버놀로지

[BAEKJOON 백준] 17406 배열 돌리기 4 본문

ALGORITM/JAVA

[BAEKJOON 백준] 17406 배열 돌리기 4

KUNDUZ 2021. 3. 3. 00:05
728x90

www.acmicpc.net/problem/17406

 

17406번: 배열 돌리기 4

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

www.acmicpc.net

문제

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

 

1 2 3

2 1 1

4 5 6

 

배열은 회전 연산을 수행할 수 있다. 회전 연산은 세 정수 (r, c, s)로 이루어져 있고, 가장 왼쪽 윗 칸이 (r-s, c-s), 가장 오른쪽 아랫 칸이 (r+s, c+s)인 정사각형을 시계 방향으로 한 칸씩 돌린다는 의미이다. 배열의 칸 (r, c)는 r행 c열을 의미한다.

예를 들어, 배열 A의 크기가 6×6이고, 회전 연산이 (3, 4, 2)인 경우에는 아래 그림과 같이 회전하게 된다.

 

회전 연산이 두 개 이상이면, 연산을 수행한 순서에 따라 최종 배열이 다르다.

다음은 배열 A의 크기가 5×6이고, 회전 연산이 (3, 4, 2), (4, 2, 1)인 경우의 예시이다.

 

배열 A에 (3, 4, 2), (4, 2, 1) 순서로 연산을 수행하면 배열 A의 값은 12, (4, 2, 1), (3, 4, 2) 순서로 연산을 수행하면 15 이다.

배열 A와 사용 가능한 회전 연산이 주어졌을 때, 배열 A의 값의 최솟값을 구해보자. 회전 연산은 모두 한 번씩 사용해야 하며, 순서는 임의로 정해도 된다.

입력

첫째 줄에 배열 A의 크기 N, M, 회전 연산의 개수 K가 주어진다.

둘째 줄부터 N개의 줄에 배열 A에 들어있는 수 A[i][j]가 주어지고, 다음 K개의 줄에 회전 연산의 정보 r, c, s가 주어진다.

출력

배열 A의 값의 최솟값을 출력한다.

제한

  • 3 ≤ N, M ≤ 50
  • 1 ≤ K ≤ 6
  • 1 ≤ A[i][j] ≤ 100
  • 1 ≤ s
  • 1 ≤ r-s < r < r+s ≤ N
  • 1 ≤ c-s < c < c+s ≤ M

DFS를 이용을 해서 회전 순서를 모든 경우를 비교를 해야한다.

 

그렇게 만들어진 순서를 이용을 해서 회전을 하게 되는데, 회전 매서드를 구현을 해서 회전을 해준다.

 

그렇게 완성된 배열에서 행을 더해서 합이 가장 적은 해를 answer에 저장해 준다.

 

 

import java.util.Scanner;

public class Main {
	
	static class Point{
		int x,y,z;

		public Point(int x, int y, int z) {
			super();
			this.x = x;
			this.y = y;
			this.z = z;
		}
		
	}
	static boolean visit[];
	static int K,N,M;
	static Point cal[];
	static int arr[][];
	static int temparr[][];
	
	public static void main(String[] args) {
		
		Scanner sc=new Scanner(System.in);
		
		N=sc.nextInt();
		M=sc.nextInt();
		K=sc.nextInt();
		temp= new Point[K];
		visit=new boolean[K];
		cal=new Point[K];
		arr=new int[N+1][M+1];
		temparr=new int[N+1][M+1];
		for (int i = 1; i <= N; i++) {
			for (int j = 1; j <= M; j++) {
				arr[i][j]=sc.nextInt();
			}
		}
		for (int i = 0; i < K; i++) {
			cal[i]=new Point(sc.nextInt(),sc.nextInt(),sc.nextInt());
		}
		
		solve(0);
		System.out.println(answer);
	}
	static Point temp[];
	static int answer=Integer.MAX_VALUE;
	private static void solve(int cnt) {
		// TODO Auto-generated method stub
		if(cnt==K) {		// 회전이 정해졌을때
			for (int i = 1; i <= N; i++) {
				for (int j = 1; j <= M; j++) {
					temparr[i][j]=arr[i][j];
				}
			}
			rotate(temp);
			for (int i = 1; i <= N; i++) {	// 행들의 합을 구해서 비교
				int result=0;
				for (int j = 1; j <= M; j++) {
					result+=temparr[i][j];
				}
				if(answer>result) {
					answer=result;
				}
			}
			return;
		}
		
		for(int i=0;i<K;i++) {
			if(visit[i])continue;
			temp[cnt]=cal[i];
			visit[i]=true;
			solve(cnt+1);
			visit[i]=false;
		}
	}
	private static void rotate(Point[] temp) {	//회전을 시켜준다.
		// TODO Auto-generated method stub
		for(int k=0;k<K;k++) {
			
			Point p=temp[k];
			for(int i=1;i<=p.z;i++) {
				int ptype=-1;
				for(int y=p.y-i;y<=p.y+i;y++) {
					if(ptype==-1) {
						ptype=temparr[p.x-i][y];
						
					}else {
						int temp1=ptype;
						ptype=temparr[p.x-i][y];
						temparr[p.x-i][y]=temp1;
					}
				}
				for(int x=p.x-i+1;x<=p.x+i;x++) {
						int temp1=ptype;
						ptype=temparr[x][p.y+i];
						temparr[x][p.y+i]=temp1;
				}
				for(int y=p.y+i-1;y>=p.y-i;y--) {
					int temp1=ptype;
					ptype=temparr[p.x+i][y];
					temparr[p.x+i][y]=temp1;
				}
				for(int x=p.x+i-1;x>=p.x-i;x--) {
					int temp1=ptype;
					ptype=temparr[x][p.y-i];
					temparr[x][p.y-i]=temp1;
				}
			}
		}
	}

}
728x90
Comments