알고리즘/문제 풀이

[Java/자바 백준 17822] 원판 돌리기

광규니 2022. 2. 17. 01:41
반응형

풀이

문제를 보면 원판이 있고, 문제도 길어서 어려워 보이지만,

사실 간단한 문제이다.

 

초기 값을 map에 입력 받고

 

1. 시계, 반시계 방향으로 몇 번 돌릴지

2. 인접한 숫자 중 같은 값이 있어주면 0으로 만들어주기

3. 인접한 숫자 중 같은 값이 없으면 평균 값을 구해 평균 값보다 크면 +1, 작으면 -1 해주는 문제

 

시계, 반시계는 forwardLotate(), reverseLotate()로 index를 하나씩 밀어주거나 땡겨주었다.

 

findEqualPoint()에서 bfs를 사용했는데, y값에 해당하는 값이 0 or M 값이 일때 조건을 줘 값을 바꿔주었다.

왜냐하면 원 형태이므로 순환하기 때문이다.

같은 값이 있으면 처리해서 point에 더해주었고

더한 point값 들을 total에서 빼주었다.

 

만약 point값이 0 이라면 onePlusMinus()에서 처리를 해주었다.

평균 값은 반올림을 하지 않으므로, float 타입으로 하여 평균값을 저장해주어 비교주었다.

 

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

public class Main {
	static int N, M, T, x, d, k, total, point, count;
	static int[][] map;	
	static Queue<int[]> queue = new LinkedList<int[]>();
	static boolean[][] visited;
	static int[] dx = {1,0,-1,0};
	static int[] dy = {0,1,0,-1};
	
	public static void main(String[] args) throws Exception{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());
		T = Integer.parseInt(st.nextToken());
		count = N * M;
		map = new int[N][M];
		
		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());
				total += map[i][j];
			}
		}
		
		for(int i = 0 ; i < T ; i++) {
			st = new StringTokenizer(br.readLine());
			// x의 배수 
			x = Integer.parseInt(st.nextToken());
			// 0 이면 시계 1 이면 반시계 
			d = Integer.parseInt(st.nextToken());
			// k 칸 
			k = Integer.parseInt(st.nextToken());
			
			for(int j = 0 ; j < k ; j++) {
				if(d == 0) forwardLotate();
				else if(d == 1) reverseLotate();
			}
			
			visited = new boolean[N][M];
			point = 0;
			for(int row = 0 ; row < N ; row++) {
				for(int col = 0 ; col < M ; col++) {
					if(map[row][col] == 0) visited[row][col] = true;
					else if(visited[row][col] == false) findEqualPoint(row, col);
				}
			}
			
			total -= point;
			if(point == 0) onePlusMinus();
		}
		System.out.println(total);
	}
	
	private static void onePlusMinus() {
		float average = (float)total / count;
		
		for(int i = 0 ; i < N ; i++) {
			for(int j = 0 ; j < M ; j++) {
				if(map[i][j] == 0 ) continue;
				else if(map[i][j] > average) {
					map[i][j] -= 1;
					total -= 1 ;
				}
				else if(map[i][j] < average) {
					map[i][j] += 1;
					total += 1;
				}
			}
		}
	}

	private static void findEqualPoint(int x, int y) {
		visited[x][y] = true;
		queue.offer(new int[] {x, y});
		int samePoint = 0;
		int tmp = map[x][y];
		while(!queue.isEmpty()) {
			int[] cur = queue.poll();
			for(int i = 0 ; i < 4 ; i++) {
				int nx = cur[0] + dx[i];
				int ny = cur[1] + dy[i];
				
				if(0 > nx || nx >= N) continue;
				if(0 > ny) ny = M-1;
				if(ny >= M ) ny = 0;
				if(visited[nx][ny]) continue;
				
				if(map[nx][ny] == tmp) {
					visited[nx][ny] = true;
					queue.offer(new int[] {nx, ny});
					samePoint += map[nx][ny];
					count -= 1;
					map[nx][ny] = 0;
  				}
			}
		}
		if(samePoint > 0) {
			map[x][y] = 0;
			count -= 1;
			samePoint += tmp;
		}
		point += samePoint;
	}

	private static void reverseLotate() {
		int plus = x;
		for(int i = x-1 ; i < N ; i += plus) {
			int tmp = map[i][0];
			for(int j = 0 ; j < M-1 ; j++) {
				map[i][j] = map[i][j+1];
			}
			map[i][M-1] = tmp;
		}
	}

	private static void forwardLotate() {
		int plus = x ;
		for(int i = x - 1; i < N ; i += plus) {
			int tmp = map[i][M-1];
			for(int j = M-1 ; j > 0 ; j--) {
				map[i][j] = map[i][j-1];
			}
			map[i][0] = tmp;
		}
	}
}

 

반응형