백준(BOJ) 1799 : 비숍
https://www.acmicpc.net/problem/1799
1799번: 비숍
첫째 줄에 체스판의 크기가 주어진다. 체스판의 크기는 10이하의 자연수이다. 둘째 줄부터 아래의 예와 같이 체스판의 각 칸에 비숍을 놓을 수 있는지 없는지에 대한 정보가 체스판 한 줄 단위로
www.acmicpc.net
N의 제한이 10이다.
바로 백트래킹이 아닐까? 라는 추측을 할 수 있다.
https://www.acmicpc.net/problem/9663
9663번: N-Queen
N-Queen 문제는 크기가 N × N인 체스판 위에 퀸 N개를 서로 공격할 수 없게 놓는 문제이다. N이 주어졌을 때, 퀸을 놓는 방법의 수를 구하는 프로그램을 작성하시오.
www.acmicpc.net
또한 이 문제와 비슷한 문제라는 것 까지 알 수 있을 것이다.
대각선에 비숍이 놓여있는지 확인하는 bool 변수를 만들기 위해 예를들어 5 x 5 보드판이 있을 때의 i + j 좌표값을
넣어보았다. 여기서 우리는 하나의 규칙을 찾을 수 있다.
바로 우측에서 좌측으로 내려오는 대각선의 좌표의 합이 모두 같다는 것!
따라서 위와 같은 방향은 x + y 번 인덱스를 확인해줌으로써 비숍이 놓여있는지 확인할 수 있을 것이다.
그렇다면 반대방향은 어떠할까??
잘 생각해보면 좌측에서 우측으로 가는 대각선의 경우 x와 y값이 모두 1씩 증가한다는 것을 알 수 있다.
따라서 같은 대각선의 경우에는 y - x 값이 일정하다.
하지만 위에서 구한 방향의 값과 겹칠 수 있기 때문에 ↙방향에서 나오는 인덱스 값과 겹치지 않도록 특정한 수를 더해준다. 내 경우에는 무난하게 큰 값인 50을 더해주었다.
이제 우리가 해야할 것은 무엇일까?
바로 그 칸에 비숍을 놓을 수 있을 때 비숍을 놓을 지 말지를 결정하는 것이다.
하지만 보드의 최대 칸 수는 100 (10 x 10)개이므로 이렇게 할 경우 2^100 의 시간복잡도가 계산되므로 시간초과가 발생하게 된다. 그렇다면 이것을 어떻게 해야할까?
체스판을 생각해 보았을 때 흰색 칸에 있는 비숍은 흰색 칸에 있는 비숍만 잡을 수 있으며 반대의 경우도 마찬가지이다.
이를 이용해 재귀함수를 두개로 나누자. 흰색 칸을 확인하고 검은색 칸을 확인한다면 해결할 수 있다.
이제 X값을 증가시켜주다가 X값이 보드에서 벗어낫을 경우를 생각해보자.
만약 X가 홀수라면 X는 늘 2씩 증가하므로 X가 1인 좌표에서 출발했다는 것을 알 수 있다.
따라서 그 다음 대각선의 X좌표는 2이므로 2로 설정하고 Y를 1증가시켜준다.
반대의 경우는 반대로 생각하면 될 것이다.
흰색칸에 있는 비숍의 경우의 최댓값과 검은색칸에 있는 비숍의 경우의 최댓값을 두번의 재귀함수를 통해 더해주어
해결할 수 있었다!
아래는 소스코드이다.
#include <bits/stdc++.h>
#define endl '\n'
#define pb push_back
#define mp make_pair
#define MOD 1000000007
#define cont continue
#define rep(i, n) for(int i = 0 ; i < (n) ; i++)
#define all(x) (x).begin(), (x).end()
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int INF = 987654321;
int N;
int board[11][11] = {};
bool flag[50] = {};
bool flag2[101] = {};
int ans = 0;
int cnt = 0;
int ans2 = 0;
int cnt2 = 0;
void solve(int y, int x) {
if(x >= N + 1) {
y++;
if(x % 2 == 0) {
x = 1;
}
else {
x = 2;
}
}
if(y > N) {
ans = max(ans, cnt);
return;
}
if(board[y][x] == 1 && flag[y + x] == false && flag2[50 + y - x] == false) {
flag[y + x] = true;
flag2[50 + y - x] = true;
cnt++;
solve(y, x + 2); // choose
cnt--;
flag[y + x] = false;
flag2[50 + y - x] = false;
}
solve(y, x + 2); // dont
}
int main() {
cin.tie(NULL);
ios_base::sync_with_stdio(false);
cin >> N;
for(int i = 1 ; i <= N ; i++) {
for(int j = 1 ; j <= N ; j++) {
cin >> board[i][j];
}
}
solve(1, 1);
ans2 += ans;
ans = 0;
solve(1, 2);
ans2 += ans;
cout << ans2 << endl;
}
'BOJ' 카테고리의 다른 글
백준(BOJ) 9660 : 돌 게임 6 (0) | 2020.06.18 |
---|---|
백준(BOJ) 1005 : ACM Craft (0) | 2020.06.16 |
백준(BOJ) 1766 : 문제집 (0) | 2020.06.16 |
백준(BOJ) 1238 : 파티 (0) | 2020.06.08 |
백준(BOJ) 5397 : 키로거 (0) | 2020.06.06 |