서양 장기인 체스에는 대각선 방향으로 움직일 수 있는 비숍(bishop)이 있다. < 그림 1 >과 같은 정사각형 체스판 위에 B라고 표시된 곳에 비숍이 있을 때 비숍은 대각선 방향으로 움직여 O로 표시된 칸에 있는 다른 말을 잡을 수 있다.
< 그림 1 >
그런데 체스판 위에는 비숍이 놓일 수 없는 곳이 있다. < 그림 2 >에서 체스판에 색칠된 부분은 비숍이 놓일 수 없다고 하자. 이와 같은 체스판에 서로가 서로를 잡을 수 없도록 하면서 비숍을 놓는다면 < 그림 3 >과 같이 최대 7개의 비숍을 놓을 수 있다. 색칠된 부분에는 비숍이 놓일 수 없지만 지나갈 수는 있다.
< 그림 2 >
< 그림 3 >
정사각형 체스판의 한 변에 놓인 칸의 개수를 체스판의 크기라고 한다. 체스판의 크기와 체스판 각 칸에 비숍을 놓을 수 있는지 없는지에 대한 정보가 주어질 때, 서로가 서로를 잡을 수 없는 위치에 놓을 수 있는 비숍의 최대 개수를 구하는 프로그램을 작성하시오.
첫째 줄에 체스판의 크기가 주어진다. 체스판의 크기는 10이하의 자연수이다. 둘째 줄부터 아래의 예와 같이 체스판의 각 칸에 비숍을 놓을 수 있는지 없는지에 대한 정보가 체스판 한 줄 단위로 한 줄씩 주어진다. 비숍을 놓을 수 있는 곳에는 1, 비숍을 놓을 수 없는 곳에는 0이 빈칸을 사이에 두고 주어진다.
풀이방법
DFS를 활용한 백트래킹 문제이다. 단순히 DFS를 사용하는 것 뿐만 아니라 어떻게 하면 더 시간을 줄일수 있는지 고민 해야하는 문제였다. 초기엔 단순히 놓을 수 있는 모든 배열을 접근하여 DFS를 돌리는 방식으로 접근했지만 시간초과를 받았다. 여기저기 검색하고 찾아본 결과, 체스판의 흰색 과 검은색 타일의 비숍은 서로 충돌할 일이 없으므로 흰타일, 검은 타일 두 가지 경우로 나누어 더한다면, N/2의 시간단축 효과를 볼 수 있었다.
void init() {
cin >> N;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
int num;
cin >> num;
board[i][j] = num;
if (num == 1) {
if (((i + j) % 2) == 1) v.push_back({ i, j });
else v2.push_back({ i, j });
}
}
}
}
void solve() {
for (int i = 0; i < v.size(); i++) dfs(i, 0, v);
int tmp = result;
result = 0;
for (int i = 0; i < v2.size(); i++) dfs(i, 0, v2);
cout << result + tmp;
}
void dfs(int index, int cnt, vector<pair<int, int>> v ) {
if (index == v.size()) {
result = max(cnt,result);
return;
}
int x = v[index].first;
int y = v[index].second;
if (chk_bishop(x, y)) {
board[x][y] = -1;
dfs(index + 1, cnt + 1, v);
board[x][y] = 1;
}
dfs(index + 1, cnt, v);
return;
}
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int N, result;
vector<pair<int, int>> v;
vector<pair<int, int>> v2;
int board[10][10] = {0,};
int direction[4][2] = { {1, 1}, {1, -1}, {-1, 1}, {-1, -1} };
void init();
void solve();
void dfs(int, int, vector<pair<int, int>>);
bool chk_bishop(int, int);
bool is_inside(int);
void init() {
cin >> N;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
int num;
cin >> num;
board[i][j] = num;
if (num == 1) {
if (((i + j) % 2) == 1) v.push_back({ i, j });
else v2.push_back({ i, j });
}
}
}
}
void solve() {
for (int i = 0; i < v.size(); i++) dfs(i, 0, v);
int tmp = result;
result = 0;
for (int i = 0; i < v2.size(); i++) dfs(i, 0, v2);
cout << result + tmp;
}
void dfs(int index, int cnt, vector<pair<int, int>> v ) {
if (index == v.size()) {
result = max(cnt,result);
return;
}
int x = v[index].first;
int y = v[index].second;
if (chk_bishop(x, y)) {
board[x][y] = -1;
dfs(index + 1, cnt + 1, v);
board[x][y] = 1;
}
dfs(index + 1, cnt, v);
return;
}
bool chk_bishop(int x, int y) {
for (int i = 1; i < N; i++) {
for (int j = 0; j < 4; j++) {
int tmp = x + (direction[j][0] * i);
int tmp2 = y + (direction[j][1] * i);
if (is_inside(tmp) && is_inside(tmp2)) {
if (board[x + (direction[j][0] * i)][y + (direction[j][1] * i)] == -1)
return false;
}
}
}
return true;
}
bool is_inside(int x) {
return (0 <= x && x < N);
}
int main() {
init();
solve();
return 0;
}