Stunning Garbanzo
open main menu
Part of series: PS

1028 BOJ

/ 3 min read

문제

접근

다이내믹 프로그래밍으로 해결하였다.

한 지점에서, 네개 방향의 대각선으로 뻗어나갈 수 있는 최대 길이를 구해 이를 반대편에 있을 지점과 비교하여 최대의 크기를 찾는 방식으로 해결하였다. 예를 들어, 오른쪽 위 대각선과 오른쪽 아래 대각선으로 각각 4와 3만큼 뻗을 수 있다면 오른쪽으로 3만큼 뻗을 수 있는 것이다. 3만큼 뻗었을 때 반대편의 대각선의 교점에서 뻗을 수 있는 길이가 3이상이면 크기가 3인 다이아몬드를 구성할 수 있다. 뻗을 수 있는 최대 길이는 각 방향으로 한번 이동했을 때의 지점에서의 최대 길이에 1을 더하면 된다.

코드

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef const ll cll;

cll R = 750, C = 750, directions[4][2] = {{-1, 1}, {1, 1}, {1, -1}, {-1, -1}};
ll r, c, diags[R][C][4];
bool mat[R][C] = {{}};
// 0, 1, 2, 3 clockwise

inline bool validCord(ll i, ll l) { return i >= 0 && i < r && l >= 0 && l < c; }

ll findDiag(ll i, ll l, ll d) {
  if (!validCord(i, l)) {
    return 0;
  } else if (diags[i][l][d] != -1) {
    return diags[i][l][d];
  }

  ll &result = diags[i][l][d], ni = i + directions[d][0],
     nl = l + directions[d][1];
  if (!mat[i][l]) {
    return result = 0;
  }

  result = 1;
  if (mat[ni][nl]) {
    result = max(result, findDiag(ni, nl, d) + 1);
  }

  return result;
}

int main(void) {
  ios::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);

  cin >> r >> c;
  for (ll i = 0; i < r; ++i) {
    cin.ignore();
    for (ll l = 0; l < c; ++l) {
      char c;
      cin >> c;
      mat[i][l] = c - '0';
    }
  }
  memset(diags, -1, sizeof(diags));

  ll result = 0;
  for (ll i = 0; i < r; ++i) {
    for (ll l = 0; l < c; ++l) {
      if (!mat[i][l]) {
        continue;
      }

      ll size = min(findDiag(i, l, 0), findDiag(i, l, 1));
      while (size > 0) {
        ll ni = i, nl = l + 2 * size - 2,
           nsize = min(findDiag(ni, nl, 2), findDiag(ni, nl, 3));

        if (size > nsize) {
          --size;
        } else {
          result = max(result, size);
          break;
        }
      }
    }
  }

  cout << result << "\n";

  return 0;
}