새소식

💻 Computer/🐘 Algorithm

[1018] 체스판 다시 칠하기 - C++

  • -

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

 

1018번: 체스판 다시 칠하기

첫째 줄에 N과 M이 주어진다. N과 M은 8보다 크거나 같고, 50보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에는 보드의 각 행의 상태가 주어진다. B는 검은색이며, W는 흰색이다.

www.acmicpc.net

이게 실버 4라고? ㅎ...

 

풀이를 시작하기전 말할 것이 있다면 나는 좀 이상하게 푼 것 같다.... 뭐지

일단 시작 하겠다.

 


풀이

( 주의! ) 처음에 문제 이해를 잘못한 나머지 항상 B 일 때만 계산했다.
왼쪽 위가 B로 시작할 때, W로 시작할 때 둘 다 계산해줘야 한다.

가장 먼저 우리가 해야 하는 8 x 8로 자를 수 있는 모오오든 경우의 수를 구해야 한다.

 

8 x 8로자를 수 있는 모오오든 경우의 수 CODE

for(int i = 0; i <= n-8; ++i){
    for(int j = 0; j <= m-8; ++j){
      // { 실행 로직.... }
    }
  }

그다음 해야 하는 것은 BFS를 구현하자

 

BFS CODE

필요한 것

  • 방문표시 배열
  • 새로운 8 x 8 배열 ( board2 )
int bfs(int i, int j, char c){
  for(int k = 0; k < 8; ++k)
    for(int w = 0; w < 8; ++w)
      board2[k][w] = board[i + k][j + w];

// 가장 처음이 보내준 문자와 다르다면 카운트를 1부터 시작 
  int cnt = (board2[0][0] != c)?1 : 0;
  
  //큐 생성
  queue<pair<int, int>> q;
  q.push({0, 0});
  dist[0][0] = 1;
  //보드에 문자 저장 후 시작
  board2[0][0] = c;

  while(!q.empty()){
    int x, y;
    tie(x, y) = q.front(); q.pop();
    
    //네 방향 검사 for문
    for(int dir = 0; dir < 4; ++dir){
      int nx = x+dx[dir];
      int ny = y+dy[dir];
      
      //배열 밖으로 나가거나 이미 방문 했던 곳이라면 continue
      if(OOB(nx, ny) || dist[nx][ny])continue;
      
      //   [B]
      //[W][B][B]
      //   [B]
      // 만약 간운데와 현재 인덱스의 문자가 같다면 바꿔준 후 cnt++
      if(board2[x][y] == board2[nx][ny]){
        board2[nx][ny] = (board2[x][y] == 'B')? 'W' : 'B';
        cnt++;
      }
      //다음 인덱스 큐에 Push
      q.push({nx, ny});
      dist[nx][ny] = 1;
    }
  }
  //8x8 보드 탐색을 끝내고 방문 표시 배열을 다시 0으로 초기화 해준다
  memset(dist, 0, 9*9*sizeof(bool));
  return cnt;
}

나는 이렇게 풀었다. 정말 비효율 적인 풀이다. 그렇지만... 나의 역량인걸....

 

Main 부분 CODE

int main(){
  init();
  cin >> n >> m;
  for(int i = 0; i < n; ++i)
    cin >> board[i];
  
  for(int i = 0; i <= n-8; ++i)
    for(int j = 0; j <= m-8; ++j)
      ans = min({ans, bfs(i, j, 'W'), bfs(i, j, 'B')});
  cout << ans;
  return 0;
}

아까 봤던 모든 경우의 수를 도는 이중 for문이 여기 사용된다.


전체 CODE

#include <bits/stdc++.h>

using namespace std;
void init(){
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
}

int n, m, ans = 2E+9;

string board[51];
char board2[9][9];
bool dist[9][9];

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

bool OOB(int nx, int ny){
  return nx < 0 || nx >= 8 || ny < 0 || ny >= 8;
}

int bfs(int i, int j, char c){
  for(int k = 0; k < 8; ++k)
    for(int w = 0; w < 8; ++w)
      board2[k][w] = board[i + k][j + w];

  int cnt = (board2[0][0] != c)?1 : 0;
  queue<pair<int, int>> q;
  q.push({0, 0});
  dist[0][0] = 1;
  board2[0][0] = c;

  while(!q.empty()){
    int x, y;
    tie(x, y) = q.front(); q.pop();
    for(int dir = 0; dir < 4; ++dir){
      int nx = x+dx[dir];
      int ny = y+dy[dir];
      if(OOB(nx, ny) || dist[nx][ny])continue;
      if(board2[x][y] == board2[nx][ny]){
        board2[nx][ny] = (board2[x][y] == 'B')? 'W' : 'B';
        cnt++;
      }
      q.push({nx, ny});
      dist[nx][ny] = 1;
    }
  }
  memset(dist, 0, 9*9*sizeof(bool));
  return cnt;
}

int main(){
  init();
  cin >> n >> m;
  for(int i = 0; i < n; ++i)
    cin >> board[i];
  for(int i = 0; i <= n-8; ++i)
    for(int j = 0; j <= m-8; ++j)
      ans = min({ans, bfs(i, j, 'W'), bfs(i, j, 'B')});
  cout << ans;
  return 0;
}

 

문제를 풀며

이게 맞나 싶었다.

실버 4라는 티어를 얕잡아 보고 "어? 이거 설계 안 하고 바로 구현 가능 할 듯!"이라고 생각한 내가 부끄럽다. 

내 코드는 정말 비효율 적이기에 배우고 싶은 아이디어를 사용하여 푸신 분의 블로그 링크를 붙여 놓겠다.

https://cryptosalamander.tistory.com/13

 

[백준 / BOJ] - 1018번 체스판 다시 칠하기 C++ 풀이

백준 - 단계별로 풀어보기 [1018] 체스판 다시 칠하기 https://www.acmicpc.net/problem/1018 문제 M*N 크기의 보드를 잘라 8x8크기의 체스판을 얻으려고 하는데, 주어진 보드에서 8x8 체스판을 만들때, 가장 적

cryptosalamander.tistory.com

어찌 이런 생각을 했는가..... 미쳐 따이

'💻 Computer > 🐘 Algorithm' 카테고리의 다른 글

[1107] 리모컨 - C++  (0) 2023.06.22
[2293] 동전 1 - C++  (0) 2023.06.21
[11502] 카드 구매하기 - c++  (0) 2023.06.19
[2302] 극장좌석 - c++  (0) 2023.06.17
[12865] 평범한 배낭 - c++  (2) 2023.06.14
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.