N-Queen(9663)
조금 더 복잡한 백트래킹 문제 1
문제
N-Queen 문제는 크기가 N × N인 체스판 위에 퀸 N개를 서로 공격할 수 없게 놓는 문제이다.
N이 주어졌을 때, 퀸을 놓는 방법의 수를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 N이 주어진다. (1 ≤ N < 15)
출력
첫째 줄에 퀸 N개를 서로 공격할 수 없게 놓는 경우의 수를 출력한다.
이게 무슨소리일까
일단 0,0으로 시작해서 한 판을 다 돌면서 확인해본 결과, dfs과정을 거치고 나면 한판의 답은 잘 나온다
그러면 이게 모든 점에서 시작해서 다 돌면서 모든 점에서의 경우의 수를 구하라? 그건가?
예제 입력
8
예제 출력
92
첫 번째 풀이는 dfs와 검사 알고리즘을 같이 한꺼번에 구현할려고 시도했었다. 하지만 그냥 검사알고리즘을 따로하고, 그 따로 알고리즘을 dfs에 넣어서 활용하는 방법을 해보라는 조언에 변경시도
풀이
import java.io.*;
import java.util.*;
public class Main{
static boolean visited[][];
static int count, N;
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
count=0;
//자바에서 boolean 배열을 생성하는 경우에 false값을 초기화되어있다!!
visited = new boolean[N][N];
dfs(visited, 0);
System.out.println(count);
}
public static void dfs(boolean [][]visited, int depth){
//이전까지의 n&m에서는 여기서 출력을 진행해줬지만 이번에는 숫자를 세는 게 포인트이기때문에 연산만.
if(depth==N){
count++;
return;
}
//기본적인 재귀를 사용하는 방식이고,
for (int i = 0; i < N; i++) {
if(fQueen(visited, depth, i)){
visited[depth][i] = true;
dfs(visited, depth+1);
visited[depth][i] = false;
}
}
}
public static boolean fQueen(boolean[][] visited, int x, int y){
//현재 점에서부터 세로를 검사해주고,
for (int i = 0; i < x; i++) {
if(visited[i][y] == true)
return false;
}
//와! for문 안에 변수를 2개나 넣어서 할 수도 있다는 사실!!!!
//원래는 이중for문써서 해볼려고하니까 그렇게 하기는 시간초과일꺼같기도하고 애초에 틀리기도해서
//이부분은 검색해봤더니 for문 안에 변수를 2개를 넣어서 해본사람이 많았다!!
//위로 대각선 검사해주고,
for (int i=x, j=y; i>=0&&j>=0; i--, j--) {
if(visited[i][j] == tru1e)
return false;
}
//아래로 대각선 검사해주고,
for (int i=x, j=y; i>=0&&j<N; i--, j++) {
if(visited[i][j] == true)
return false;
}
return true;
}
}
2번째 시도
import java.util.*;
import java.io.*;
public class Main{
static int n, sum=0;
static int[][] arr;
static boolean[][] visited;
public static void main(String[] args) throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
n = Integer.parseInt(br.readLine());
//퀸의 위치를 기억하기 위한 배열
arr = new int[n][n];
//퀸이 지나갈 수 있는 곳을 기억하기 위한 배열
visited = new boolean[n][n];
//깊이우선탐색
dfs(0);
System.out.println(sum);
}
public static void dfn(int cnt){
//만약 찾고있는 깊이가 한계까지 도달한다면 결과값 ++
if(cnt == n){
sum++;
return;
}
for(int i=0; i<n; i++){
//여기서부터는 기존 dfs의 구현과 유사하다
//일단 만약 체크를 했던 장소라면 넘어가고
if(visited[cnt][i])
continue;
//해당 위치에 들렀다고 체크하고
visited[cnt][i] = true;
//체크를 했으니까 퀸의 위치또한 저장해두고 진행
arr[cnt][i] = 1;
//퀸이 움직일 수 있는 곳을 모두 체크
QueenMove(cnt, i);
//재귀를 통해서 다음 dfs로 진행
dfs(cnt+1);
//만약 깊이가 끝까지 진행되었다면, return을 했을테지만 그냥 진행이 되었다면 여기까지 올 수 있음
//여기까지 도달했다는 의미는 퀸의 배치를 완료했다는 의미이다.
//다시 원상복구를 해줘야한다.
//체스판을 초기화 시키고
for(int j=0; j<n; j++){
for(int k=0; k<n; k++){
visited[j][k] = false;
}
}
//퀸을 빼주고
arr[cnt][i] = 0;
//이전에 두었던 퀸의 위치를 복원시켜준다
for(int j=0; j<n; j++){
for(int k=0; k<n; k++){
if(arr[j][k] == 1){
QueenMove(j, k);
}
}
}
}
}
//좌표를 생각하는게 반대이다..!
public static void QueenMove(int x, int y){
//세로로 움직이면서 확인
for(int i=x; i<n; i++){
if(!visited[i][y])
visited[i][y] = true;
}
//왼쪽 아래 대각선으로 확인
for(int i=x, j=y; i<n&&j<n; i++, j++){
if(!visited[i][j])
visited[i][j] = true;
}
//오른쪽 아래 대각선으로 확인
for(int i=x, j=y; i<n&&j>=0; i++, j--){
if(!visited[i][j])
visited[i][j] = true;
}
}
}
dfs의 구조를 조금씩은 알게되어가고 있어서 다행이면 다행이다..!
하지만 어려워서 쉽게 해결하지 못했던 문제이다...
Last updated
Was this helpful?