[삼성기출]백준17822 - 원판돌리기

 
by 박신종

이 문제는 시뮬 + bfs로 풀었습니다.


package sw;

import java.io.*;
import java.util.*;

public class Main17822_원판돌리기 {
	
	static int N,M,T;
	static int[][] map;
	static int[][] dir = // 우하좌상
	static boolean check(int x, int y) {
		if(x>=0 && x<N && y>=0 && y<M)
			return true;
		else return false;
	}
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String[] input = br.readLine().trim().split(" ");
		N = Integer.parseInt(input[0]);
		M = Integer.parseInt(input[1]);
		T = Integer.parseInt(input[2]);
		
		map = new int[N][M];
		String[] str = null;
		for(int i=0; i<N; i++) {
			str = br.readLine().trim().split(" ");
			for(int j=0; j<M; j++) {
				map[i][j] = Integer.parseInt(str[j]);
			}
		}
		float avg=0;
		int x,d,k;
		for(int i=0; i<T; i++) {
			str = br.readLine().trim().split(" ");
			x = Integer.parseInt(str[0]);
			d = Integer.parseInt(str[1]); // 0시계, 1반시계
			k = Integer.parseInt(str[2]);
			
			// 회전
			for(int j=0; j<N; j++) { // x의 배수 라인을 d방향으로 k만큼 회전 회전
				if((j+1)%x==0) {
					rotate(j,d,k);
				}
			}
			
			// 인접한 번호 지워주고, 지울게 없다면 평균값 계산하여 원판에 적용
			avg = deleteAndAvg(); // 인접한게 있다면 -1, 없다면 평균값 준다.
			if(avg != -1) { // 인접한게 없을 때 계산.
				calc(avg);
			}
		}
		System.out.println(result());
	}
	
	// 최종 원판에 남은 번호 계산.
	static int result() {
		int res=0;
		for(int i=0; i<N; i++) {
			for(int j=0; j<M; j++) {
				if(map[i][j] != -1) {
					res+=map[i][j];
				}
			}
		}
		return res;
	}
	
	// 평균값으로 원판 넘버에 적용. 이때 평균값은 소수자리까지 계산.
	static void calc(float avg) {
		for(int i=0; i<N; i++) {
			for(int j=0; j<M; j++) {
				if(map[i][j] != -1) {
					if(map[i][j] > avg) map[i][j]-=1;
					else if(map[i][j] < avg) map[i][j]+=1;
				}
			}
		}
	}
	 
	
	//회전
	static void rotate(int x, int d, int k) {
		int s=0;
		int[] set = new int[M];
		if(k % M == 0) return;
		if(d==0) { // 시계방향
			s = k % M;
			
		}else if(d==1) { // 반시계 방향
			s = M - k%M;
		}
		for(int i=0; i<M; i++) {
			set[(s+i)%M] = map[x][i];
		}
		map[x] = set;
	}
	
	//인접한 넘버 지우고 평균값 계산.
	static float deleteAndAvg() {
		int num=0;
		int sum=0;
		int cnt=0;
		int flag = 0;
		for(int i=0; i<N; i++) {
			for(int j=0; j<M; j++) {
				if(map[i][j] != -1) {
					num = bfs(i,j); // bfs로 인접한 넘버 지우기.
					if(num == -1) { // 인접했다면
						flag++;
					} else {
						sum += num; // 인접하지 않았다면 그 숫자 다 더해주기.
						cnt++;		// 평균값 내기위한 작업.
					}
				}
			}
		}
		return flag>0?-1:(float)sum/cnt; // 인접한게 있다면 -1, 인접한게 없다면 avg 리턴
	}
	
	static int bfs(int x, int y) {
		Queue<Pos> qu = new LinkedList<>();
		qu.add(new Pos(x,y));
		int num = map[x][y];
		Pos p = null;
		int dx,dy;
		boolean flag = false;
		while(!qu.isEmpty()) {
			p = qu.poll();
			for(int d=0; d<4; d++) {
				dx = p.x + dir[d][0];
				dy = p.y + dir[d][1];
				dy = (M+dy)%M;	// 좌우는 원형으로 비교.
				if(check(dx,dy) && num == map[dx][dy]) {
					qu.add(new Pos(dx, dy));
					map[dx][dy] = -1;
					flag = true;
				}
			}
		}
		if(flag) map[x][y] = -1;
		return map[x][y];
	}
	
	static void print() {
		System.out.println();
		for(int i=0; i<N; i++) {
			for(int j=0; j<M; j++)
				System.out.print(map[i][j]+" ");
			System.out.println();
		}
		System.out.println("=====================");
	}
	
	static class Pos{
		int x,y;

		public Pos(int x, int y) {
			this.x = x;
			this.y = y;
		}

		@Override
		public String toString() {
			return "[" + x + "," + y + "]";
		}
		
	}
}