알고리즘/softeer

Softeer / [인증평가(2차) 기출] Garage game

유이얼 2023. 1. 23. 01:02

https://softeer.ai/practice/info.do?idx=1&eid=540 

 

Softeer

연습문제를 담을 Set을 선택해주세요. 취소 확인

softeer.ai

#include <iostream>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <string.h>

using namespace std;

using vi = vector<int>;
using vvi = vector<vi>;
using pii = pair<int, int>;

int N;
int ans;
int board[45][15];
vi history;


bool valid(int cy, int cx, int n) {
  return 0 <= cy && cy < n && 0 <= cx && cx < N;
}

void arrange(int grid[45][15], int depth, map<int, int>& columns) {
  if (depth >= 3) return;

  for (auto t : columns) {
    int cy = t.second;
    int cx = t.first;

    int ny = cy;
    for (int k = cy + 1; k < 3 * N; ++k) {
      if (grid[k][cx] == 0) continue;
      grid[ny++][cx] = grid[k][cx];
      grid[k][cx] = 0;
    }
  }
}

bool isWorst(int grid[45][15], int depth) {
  int dir[] = { 0, 1, 0, -1 };
  int limit = 4 - depth;

  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < N; ++j) {
      for (int k = 0; k < 3; ++k) {
        int nx = j + dir[k + 1];

        for (int t = 0; t < limit; ++t) {
          int ny = i + dir[k] + t;
          if (!valid(ny, nx, 3 * N)) continue;
          if (grid[i][j] == grid[ny][nx])
            return false;
        }
      }
    }
  }

  return true;
}

void solve(int grid[45][15], int depth, int result);

void f(bool visit[15][15], int grid[45][15], int cy, int cx, int depth, int result) {
  queue<pii> que;
  que.push({ cy, cx });
  visit[cy][cx] = true;
  int color = grid[cy][cx];
  grid[cy][cx] = 0;
  history[depth - 1] = color;
  map<int, int> columns;
  columns[cx] = cy;

  int count = 1;
  int left = cx, right = cx, top = cy, bottom = cy;

  int dir[] = { -1, 0, 1, 0, -1 };

  while (!que.empty()) {
    auto t = que.front();
    que.pop();

    for (int i = 0; i < 4; ++i) {
      int ny = t.first + dir[i];
      int nx = t.second + dir[i + 1];
      if (!valid(ny, nx, N)) continue;
      if (grid[ny][nx] != color) continue;

      que.push({ ny, nx });
      grid[ny][nx] = 0;
      visit[ny][nx] = true;
      ++count;
      left = min(left, nx);
      right = max(right, nx);
      top = max(top, ny);
      bottom = min(bottom, ny);
      if (!columns.count(nx) || columns[nx] > ny)
        columns[nx] = ny;
    }
  }

  result += count + (right - left + 1) * (top - bottom + 1);

  arrange(grid, depth, columns);

  solve(grid, depth + 1, result);
}

void solve(int grid[45][15], int depth, int result) {
  if (depth >= 4) {
    ans = max(ans, result);
    return;
  }

  if (isWorst(grid, depth)) {
    ans = max(ans, result + (4 - depth) * 2);
    return;
  }

  if (ans >= N * N * 2 * (4 - depth) + result)
    return;

  int next_grid[45][15] = { 0, };
  bool visit[15][15] = { 0, };

  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < N; ++j) {
      if (visit[i][j]) continue;

      memcpy(next_grid, grid, sizeof(next_grid));
      f(visit, next_grid, i, j, depth, result);
    }
  }
}

int main() {
  std::ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);

  cin >> N;
  history.resize(3);

  for (int i = 3 * N - 1; i >= 0; --i) {
    for (int j = 0; j < N; ++j) {
      cin >> board[i][j];
    }
  }

  // how to pass the worst-case?

  /*if (colors.size() == 3 * N * N) {
    cout << 6 << '\n';
    return 0;
  }*/

  solve(board, 1, 0);
  cout << ans << '\n';
  return 0;
}

 

- 배열 대신 vector 이용 시, 시간 초과 발생

- worst case 이외에, worst case 와 유사한 (그러나 worst case 는 아닌,) 테스트셋이 없다