파게로그

[백준 1018번] 체스판 다시 칠하기 본문

콤퓨타 왕왕기초/PS

[백준 1018번] 체스판 다시 칠하기

파게 2020. 11. 6. 21:22

문제 링크: 1018번 체스판 다시 칠하기

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

 

체스판과 같은 크기로, 2차원 int 배열을 먼저 다음과 같이 2개 더 만든다.

B로 시작하는 체스판, W로 시작하는 체스판에 대해서 각각의 칸에,

다시 칠해야 할 때 1, 다시 칠하지 않아도 될 때 0을 넣는다.

 

가로 8칸, 세로 8칸을 잘라낼 때 기준은 좌상단 모서리의 좌표로 설정했다.

이 좌표, 즉 board[row][col]의 row, col의 범위는 0<=row<=n-8, 0<=col<=m-8이다.

좌상단 모서리를 옮겨가면서 잘라낸 체스판에 들어있는 1의 개수를 모두 더하면 된다.

 

근데 이걸 그대로 하면 O(n^3)이 되니까...

지그재그로 1행 또는 1열만 갱신해나가면서 계산할 수 있다.

다만 구현이 너무 복잡해지니까 차선책으로 행이 바뀔 때는 새로 계산하고, 열이 바뀔 때는 1열만 갱신했다.

 

잘라낸 체스판 열 별로 계산한 값을 colsum에 저장하되,

colsum 길이를 m으로 설정해두고,

colsum의 합을 구할 때는 좌상단 모서리가 오른쪽으로 움직일 때마다 시작점과 끝점을 계속해서 1씩 증가시킨다.

 

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

int getMin(int a, int b) {
	if (a < b) return a;
	else return b;
}

int getArrSum(int *arr, int start, int finish) {
	int sum = 0;
	for (int i = start; i <= finish; i++) {
		sum += arr[i];
	}
	return sum;
}

void getFirstColsum(int **arr, int i, int n, int m, int *colsum) {
	for (int c = 0; c < 8; c++) {
		for (int r = i; r < i + 8; r++) {
			colsum[c] += arr[r][c];
		}
	}
}

void getRepaint(int **arr, int n, int m, int *answer) {
	for (int i = 0; i <= n - 8; i++) {
		// 새 행에 진입할 때마다 colsum 새로 채우기
		int *colsum = (int *)(malloc(sizeof(int)*m));
		for (int t = 0; t < 8; t++) colsum[t] = 0;

		getFirstColsum(arr, i, n, m, colsum);
		*answer = getMin(getArrSum(colsum, 0, 7), *answer);

		int start = 0, finish = 7;
		for (int j = 1; j <= m - 8; j++) { // 자를 부분을 오른쪽으로 1칸 옮기기
			for (int t = i; t < i + 8; t++) {
				colsum[finish + 1] += arr[t][j + 7];
			}
			*answer = getMin(getArrSum(colsum, start + 1, finish + 1), *answer);
			start++; finish++;
		}
	}
}

void fill_arr(int **arr, int n, int m, char start, char **board) {
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if ((i % 2 == 0 && j % 2 == 0) || (i % 2 == 1 && j % 2 == 1)) {
				if (board[i][j] == start) {
					arr[i][j] = 0;
				}
				else {
					arr[i][j] = 1;
				}
			}
			else {
				if (board[i][j] != start) {
					arr[i][j] = 0;
				}
				else {
					arr[i][j] = 1;
				}
			}
		}
	}
}

void printArr(int **arr, int n, int m) {
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			cout << arr[i][j];
		}
		cout << '\n';
	}
}

int main() {
	/* 입력 */
	int n, m; cin >> n >> m;
	char **board = (char **)(malloc(sizeof(char *)*n));
	for (int i = 0; i < n; i++) {
		board[i] = (char *)(malloc(sizeof(char)*m));
		scanf("%s", board[i]);
	}

	/* arr_bw, arr_wb 만들기 */
	int **arr_bw = (int **)(malloc(sizeof(int *)*n));
	int **arr_wb = (int **)(malloc(sizeof(int *)*n));
	for (int i = 0; i < n; i++) {
		arr_bw[i] = (int *)(malloc(sizeof(int)*m));
		arr_wb[i] = (int *)(malloc(sizeof(int)*m));
		for (int j = 0; j < m; j++) {
			arr_bw[i][j] = 0;
			arr_wb[i][j] = 0;
		}
	}

	fill_arr(arr_bw, n, m, 'B', board);
	fill_arr(arr_wb, n, m, 'W', board);

	/* 다시 칠해야 하는 정사각형의 개수 구하기 */
	int answer = 65;
	getRepaint(arr_bw, n, m, &answer);
	getRepaint(arr_wb, n, m, &answer);

	cout << answer;

	return 0;
}

'콤퓨타 왕왕기초 > PS' 카테고리의 다른 글

[정렬] heap sort  (0) 2020.11.06
[백준 1436번] 영화감독 숌  (0) 2020.11.06
[백준 7568번] 덩치  (0) 2020.11.05
[백준 2168번] 타일 위의 대각선  (0) 2020.11.03
[백준 11729번] 하노이의 탑  (0) 2020.11.02
Comments