본문 바로가기

C언어/자료구조

5-4장 8퀸 문제

1. 8퀸 문제 정의하기 

 

- 서로 공격하여 잡을 수 없도록 8개의 퀸을 8x8 체스판에 놓으세요

- 퀸은 가로,세로, 대각선 방향으로 체스판 끝까지 이동 가능

- 규칙 

1) 각 열에 퀸을 1개만 배치 

2) 각 행에 퀸을 1개만 배치 

 

2. 가지 뻗기(branching)

 

- 가지를 뻗으며 퀸을 배치하는 조합 모두 나열

- 배열 pos는 퀸의 배치를 나타냄 

- i열에 놓인 퀸의 위치가 j행이면 pos[i]의 값을 j로 함

 

- set함수 

 -> pos[i]에 0부터 7까지의 값을 순서대로 대입하여 'i열에 퀸을 1개만 배치하는 8가지 조합을 만드는 재귀함수'

 -> 0번째 열에 퀸을 배치 

set(0); //0열에 퀸을 배치

 -> for문에 의한 반복 구문에서는 i값을 0에서 7까지 증가시키면서 pos[i]에 j를 대입함으로써 퀸을 j행에 배치 

 -> 0번째 열이 확정 

set(i+1); //다음 열에 퀸을 배치

 

 ->앞에서 했던 작업을 다음열인 1열에서 수행

 ->i가 7이 되어 8개의 퀸이 모두 배치 될때까지 재귀호출 

 

print 함수 

 - 퀸이 배치된 위치 출력

 - pos의 배열 요솟값 출력

 

//각 열에 1개의 퀸을 배치하는 조합을 재귀적으로 나열
#include <stdio.h> 

int pos[8]; // 각 열에서 퀸의 위치

//각 열의 퀸의 위치를 출력
void print(void)
{
	for(int i=0; i<8; i++)
		printf("%2d",pos[i]);
	putchar('\n');
}

//i열에 퀸을 배치 
void set(int i) 
{
	for(int j=0; j <8; j++)
	{
		pos[i]=j;
		if(i==7)
			print();
		else
			set(i+1);
	}
}

int main()
{
	set(0); //0열에 퀸을 배치 
	
	return 0; 
}

 

3. 분기 한정법 다루기 

 

- 규칙 2) 각 행에 퀸을 1개만 배치 를 적용하여 분기 한정

- 필요하지 않은 분기를 줄여 불필요한 

 

- flag[]

 -> 같은 행에 중복하여 퀸이 배치되는 것을 방지하기 위한 표시 

 -> j행에 퀸을 배치하면 flag[j]의 값을 1로 하고 배치되지 않은 상태의 값은 0으로 함 

 

-set함수는 퀸을 배치하지 않은 행(flag[i]값이 0인 행)에만 퀸을 배치 

 

-한정 조작(bounding)

 -> 필요하지 않은 분기를 없애 불필요한 조합을 줄이는 방법 

 

- 분기 한정법 (branching and bounding method)

 -> 가지 뻗기와 한정 조작을 조합하여 문제를 풀어나감

 

ex)

- 0열에 퀸을 배치하기 위해 호출한 set 함수는 먼저 0행에 퀸을 배치 (flag[0] =0)

- 0행에 퀸을 배치했기 때문에 flag[0]의 값을 1로 변경

 

- set(i+1) 호출 -> 1열에 퀸을 배치 

 -> 0행에 퀸 배치?

  flag[0]의 값이 1이므로 배치 x

  set함수 재귀호출 x

 

 ->1행에 퀸 배치?

  flag[1]=0이므로 아직 배치 되지 않은 상태 

  1행에 퀸 배치 

   set함수를 재귀호출하여 다음 열인 2번째에 퀸을 배치 

 

//각 행, 각 열에 1개의 퀸을 배치하는 조합을 재귀적으로 나열
#include <stdio.h> 

int flag[8]; //각 행에 퀸을 배치했는지 체크하는 배열
int pos[8]; //각 열에서의 퀸의 위치 

//각 열에서 퀸의 위치를 출력
void print() 
{
	for(int i=0; i<8; i++)
	printf("%2d",pos[i]);
	putchar('\n');
}

//i열에서 알맞은 위치에 퀸을 배치 
void set(int i) 
{
	for(int j=0; j<8; j++) {
		if(!flag[j]) { //j행에 퀸을 배치 하지 않았다면
			pos[i] =j;
			if(i==7)
				print(); //모든 열에 배치를 마침
			else {
				flag[j]==1; 
				set(i+1); //다음 열에 배치 
				flag[j]==0;
			} 
		}
	}
}

int main()
{
	for(int i=0; i<8; i++)
		flag[i]=0;
	set(0);
	
	return 0;
}

 

4. 8퀸 문제를 푸는 프로그램 완성하기 

 

- 퀸은 대각선방향으로도 이동할 수 있기 때문에 어떤 대각선에서 보더라도 1개만 배치하는 한정조작 추가 

 

- flag_b[]

 j행 i열의 값은 i+j

 '/' 방향의 대각선 위에 퀸을 배치했는지 체크 

- flag_c[]

  j행 i열의 값은 i-j+7

 '\' 방향의 대각선 위에 퀸을 배치했는지 체크 

- 각 칸에 퀸의 배치를 체크할 때 1) 같은 행에 퀸을 배치했는지 2) '/' 대각선 방향에 퀸을 배치했는지 3) '\' 대각선 방향에 퀸을 배치했는지 판단

 

//8퀸 문제 풀이 
#include <stdio.h> 

int flag_a[8]; //각 행에 퀸을 배치했는지 체크하는 배열
int flag_b[15]; // 대각선 /에 퀸을 배치했는지 체크하는 배열
int flag_c[15]; // 대각선 \에 퀸을 배치했는지 체크하는 배열
int pos[8]; //각 열에서 퀸의 위치 

//각 열에서 퀸의 위치를 출력 
void print() 
{
	for(int i=0; i<8; i++)
		printf("%2d",pos[i]);
	putchar('\n');
}

//i열에서 알맞은 위치에 퀸을 배치 
void set(int i) 
{
	for(int j=0; j<8; j++) {
		if(!flag_a[j]&&!flag_b[i+j]&&!flag_c[i-j+7]) {
			pos[i]=j; 
			if(i==7)  //모든 열에 배치를 마침  
				print();
			else {
				flag_a[j]=flag_b[i+j]=flag_c[i-j+7]=1;
				set(i+1); //다음 열에 배치 
				flag_a[j]=flag_b[i+j]=flag_c[i-j+7]=0;
			}
		}
	}
}

int main()
{
	for(int i=0; i<8; i++)
		flag_a[i]=0;
	for(int i=0; i<15; i++)
		flag_b[i]=flag_c[i]=0;
	set(0); //0열에 배치 
	
	return 0; 
}

 

'C언어 > 자료구조' 카테고리의 다른 글

6-2장 버블 정렬  (0) 2023.07.28
6-1장 정렬  (0) 2023.07.28
5-3장 하노이의 탑  (0) 2023.07.27
5-2 재귀 알고리즘 분석  (0) 2023.07.27
5-1 재귀의 기본  (0) 2023.07.27