일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 비트마스크
- 피보나치 수
- dfs
- 백트래킹
- 우선순위 큐
- 링크드리스트
- 스택
- MST
- DP
- 중복 순열
- lis
- 메모리풀
- 크루스칼
- BFS
- 재귀
- 문자열
- 이분 탐색
- 조합
- 분할 정복
- Knapsack
- 큐
- 빠른 입출력
- 그리디
- 순열
- 클래스
- 시뮬레이션
- 세그먼트 트리
- 완전 탐색
- BeautifulSoup
- SSAFY
- Today
- Total
작심 24/7
[백준] 17822번 원판 돌리기 본문
17822번: 원판 돌리기
반지름이 1, 2, ..., N인 원판이 크기가 작아지는 순으로 바닥에 놓여있고, 원판의 중심은 모두 같다. 원판의 반지름이 i이면, 그 원판을 i번째 원판이라고 한다. 각각의 원판에는 M개의 정수가 적혀
www.acmicpc.net
이차원 배열 arr[i][j]에서
i는 원판의 번호, j는 12시부터 시계 방향으로 돌아는 형태로 간주하였다.
1. 시계 방향이나 반시계 방향으로 K칸 회전시키는데
만약 M이 4인 원판이면 4칸 회전시키면 처음 상태로 돌아온다.
M이 6인 원판은 6칸 회전 시키면 처음 상태로 돌아온다.
그러므로 불필요하게 원판을 여러 번 돌리는 경우를 막기 위해서
원판을 K%M칸 만큼 회전시키도록 한다.
한 번 회전이 끝나면
2. 각 좌표마다 상, 하, 좌, 우 방향으로 인접하면서
수가 같은 것을 찾아다니며 체크한다.
arr[i][j]와 상, 하로 인접한 수는 인접한 원판에 있는 수이다.
만약 그 방향이 배열 범위를 벗어난다면
그 방향에 있는 원판이 존재하지 않는 경우이므로 다른 방향으로 넘어간다.
ex) arr[0][j]의 위쪽 방향은 arr[-1][j]가 되는데 -1번째 원판은 존재하지 않는다.
arr[i][j]와 좌, 우로 인접한 수는 같은 원판에 있는 수이다.
그 방향이 배열 범위를 벗어나도 원형 표현의 한계일 뿐
같은 원판에 있기 때문에 인접한 수가 두 개인 사실은 변하지 않으므로
경우에 맞게 값을 바꿔준다.
ex) arr[i][0]의 왼쪽 방향은 arr[i][-1]라고 되어있지만
실제 그림에서 보면 arr[i][0]의 왼쪽 방향은 arr[i][M-1]이다.
마찬가지로 arr[i][M-1]의 오른쪽 방향은 arr[i][M]이라고 되어있지만
실제 그림에서 보면 arr[i][M-1]의 오른쪽 방향은 arr[i][0]이다.
3. 인접한 수가 한 개 이상 있다면
그 수를 0으로 만들어주고
인접한 수가 없다면
전체 원판에 남은 수들의 평균을 구해서
평균보다 큰 수는 -1, 작은 수는 +1 해준다.
4. T번 회전이 끝나면 남은 수들의 합을 출력한다.
#include <iostream>
#include <algorithm>
using namespace std;
int N, M, T, X, D, K, x, y, cnt, res;
int arr[51][51], dx[4] = { -1, 1, 0, 0 }, dy[4] = { 0, 0, -1, 1 };
void Clockwise(int k, int num) { for (int i = 0; i < k; i++) for (int j = 0; j < M - 1; j++) swap(arr[num][M - 1], arr[num][j]); }
void CounterClockwise(int k, int num) { for (int i = 0; i < k; i++) for (int j = M - 1; j > 0; j--) swap(arr[num][0], arr[num][j]); }
int main() {
cin >> N >> M >> T;
for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) cin >> arr[i][j];
for (int t = 0; t < T; t++) {
cin >> X >> D >> K;
for (int i = 2; i <= N; i++) { // X 배수 번호 원판들 돌린다
if (i % X == 0) {
if (D) CounterClockwise(K % M, i - 1);
else Clockwise(K % M, i - 1);
}
}
bool chk[51][51] = { false };
cnt = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (!arr[i][j]) continue;
for (int k = 0; k < 4; k++) {
x = i + dx[k], y = j + dy[k];
if (x < 0 || x > N) continue; // 인접한 원판이 없는 경우는 넘긴다 (1번째나 M번째 원판일 경우)
if (y < 0) y = M - 1;
else if (y > M) y = 0;
if (arr[i][j] == arr[x][y]) chk[i][j] = chk[x][y] = true, cnt++; // 인접한 수가 같은 경우 체크
}
}
}
if (!cnt) { // 인접한 수가 없을 경우 평균에 따라서 값 변경
double avg = 0, cnt2 = 0;
for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) if (arr[i][j] != 0) avg += arr[i][j], cnt2++;
avg /= cnt2;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (arr[i][j] != 0 && (double)arr[i][j] > avg) arr[i][j] -= 1;
else if (arr[i][j] != 0 && (double)arr[i][j] < avg) arr[i][j] += 1;
}
}
}
else for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) if (chk[i][j]) arr[i][j] = 0; // 인접한 수가 있을 경우 0으로 변경
}
for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) res += arr[i][j];
cout << res;
return 0;
}
'백준' 카테고리의 다른 글
[백준] 16637번 괄호 추가하기 (0) | 2020.08.13 |
---|---|
[백준] 17825번 주사위 윷놀이 (0) | 2020.08.06 |
[백준] 11659번 구간 합 구하기 4 (0) | 2020.08.03 |
[백준] 19237번 어른 상어 (0) | 2020.08.03 |
[백준] 17837번 새로운 게임 2 (0) | 2020.07.31 |