컴퓨터기본/문제풀이

[백준] 17822번: 원판 돌리기

차가운오미자 2021. 11. 20. 10:35

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

 

17822번: 원판 돌리기

반지름이 1, 2, ..., N인 원판이 크기가 작아지는 순으로 바닥에 놓여있고, 원판의 중심은 모두 같다. 원판의 반지름이 i이면, 그 원판을 i번째 원판이라고 한다. 각각의 원판에는 M개의 정수가 적혀

www.acmicpc.net

나머지 예제 생략

 

문제 이해

원판을 배열로 생각하면 된다. 

  • Turn_Plate(): 방향에 맞춰서 해당되는 행을 회전시킨다.
  • Erase_Duplicates():
    • 판(pan)의 모든 칸에 대해서 4방향 탐색을 한다. 만약 같은 숫자가 있으면 tmppan 배열에 -1이라고 표시를 해준다.
    • 이때, 열의 끝이 연결되어 있으므로, 열의 범위를 벗어나면 다시 돌아서 행의 반대 끝이 되도록 한다.
      (M --> 0, -1 --> M-1)
    • 탐색을 완료했으면 -1이 되어있는 칸들을 pan에서 지워준다. 
  • Add_Sub_Avg() : 평균을 구하고, 평균보다 큰 애들은 -1, 작은 애들은 +1 해준다.
  • Get_Answer() : 판의 모든 값을 더한다. 

 

작성 코드

#include <stdio.h>
#include <string.h>
#define MAXN 50
#define MAXM 50
int N, M, T;
int pan[MAXN+5][MAXM+5];
int tmppan[MAXN+5][MAXM+5];
int tmp[MAXM + 5];
struct {
	int x, d, k; // x번 원판을 d방향으로 k번 움직임
}cmd[50 + 2];

void Get_Input(void) {
	scanf("%d %d %d", &N, &M, &T);
	for (int i = 1; i <= N; i++) {
		for (int j = 0; j < M; j++) {
			scanf("%d", &pan[i][j]);
		}
	}
	for (int i = 0; i < T; i++) {
		scanf("%d %d %d", &cmd[i].x, &cmd[i].d, &cmd[i].k);
	}
}

void Turn_Plate(int x, int d, int k) {
	// x의 배수인 원판을 d방향으로 k번 움직임
	int a = (d == 0) ? 1 : -1;
	for(int i = 1; i<=N; i++){
		if (i % x != 0) continue;
		memset(tmp, 0, sizeof(tmp));
		for(int j = 0; j<M; j++){
			tmp[(j + ((a * k)%M) + M) % M] = pan[i][j];
		}
		memcpy(pan[i], tmp, sizeof(tmp));
	}
}

int dy[] = { 0, 0, 1, -1 };
int dx[] = { 1, -1, 0, 0 };

int Erase_Duplicates() {
	int cnt = 0;
	// 모든 좌표에 대해서 4방 탐색하면 됨
	memset(tmppan, 0, sizeof(tmppan));
	for (int i = 1; i <= N; i++) {
		for (int j = 0; j < M; j++) {
			if (pan[i][j] == -1) continue;
			for (int k = 0; k < 4; k++) {
				int ny = dy[k] + i;
				int nx = dx[k] + j;
				if (ny < 1 || ny > N) continue; 
				if (nx == -1) nx = M - 1;
				if (nx == M) nx = 0;
				if (pan[i][j] == pan[ny][nx]) {
					tmppan[i][j] = -1;
					break;
				}
			}
		}
	}

	for (int i = 1; i <= N; i++) {
		for (int j = 0; j < M; j++) {
			if (tmppan[i][j] == -1) {
				pan[i][j] = -1;
				cnt++;
			}
		}
	}
	return cnt;
}

void Add_Sub_Avg() {
	int sum = 0, cnt = 0;
	double avg;
	for (int i = 1; i <= N; i++) {
		for (int j = 0; j < M; j++) {
			if (pan[i][j] != -1) {
				sum += pan[i][j];
				cnt++;
			}
		}
	}
	avg = (sum * 1.0) / cnt;
	for (int i = 1; i <= N; i++) {
		for (int j = 0; j < M; j++) {
			if (pan[i][j] != -1) {
				if ((double)pan[i][j] > avg) pan[i][j] -= 1;
				else if ((double)pan[i][j] < avg) pan[i][j] += 1;
			}
		}
	}
}

int Get_Answer() {
	int sum = 0;
	for (int i = 1; i <= N; i++) {
		for (int j = 0; j < M; j++) {
			if (pan[i][j] != -1) {
				sum += pan[i][j];
			}
		}
	}
	return sum;
}

 int main(void) {
	 Get_Input();
	 for (int i = 0; i < T; i++) {
		 Turn_Plate(cmd[i].x, cmd[i].d, cmd[i].k);
		 if(!Erase_Duplicates()) Add_Sub_Avg();
	 }
	 printf("%d", Get_Answer());
	 return 0;
}

'컴퓨터기본 > 문제풀이' 카테고리의 다른 글

[백준] 18808번: 스티커 붙이기  (0) 2021.11.20
[백준] 17825번: 주사위 윷놀이  (0) 2021.11.20
[백준] 17779번: 게리맨더링 2  (0) 2021.11.19
[백준] 17281번: ⚾  (0) 2021.11.18
[백준] 16985번: Maaaaaaaaaze  (0) 2021.11.18