Hầu hết mọi người không lạ gì với bài toán 8-quân hậu vì tính dễ hiểu và có thể nó giống như một trò chơi vui, trí tuệ. Tuy nhiên không phải ai cũng viết nhiều vấn đề thú vị xung quanh nó (xét ở một góc độ nào đó nó giống như định lý Ferma: Định lý này đã làm hao mòn không biết bao bộ óc vĩ đại của các nhà toán học lừng danh trong gần 4 thế kỉ. Cuối cùng nó được chứng minh bởi Andrew Wiles năm 1993 sau gần 8 năm ròng nghiên cứu, phát triển chứng minh các giả thiết có liên quan[Fermat]).

 

 

Hầu hết mọi người không lạ gì với bài toán 8-quân hậu vì tính dễ hiểu và có thể nó giống như một trò chơi vui, trí tuệ. Tuy nhiên không phải ai cũng viết nhiều vấn đề thú vị xung quanh nó (xét ở một góc độ nào đó nó giống như định lý Ferma: Định lý này đã làm hao mòn không biết bao bộ óc vĩ đại của các nhà toán học lừng danh trong gần 4 thế kỉ. Cuối cùng nó được chứng minh bởi Andrew Wiles năm 1993 sau gần 8 năm ròng nghiên cứu, phát triển chứng minh các giả thiết có liên quan[Fermat]).

Bài toán quân hậu có thể được phát biểu như sau:

Bài toán tám quân hậu là bài toán đặt tám quân hậutrên bàn cờ vua kích thước 8×8 sao cho không có quân hậu nào có thể "ăn" được quân hậu khác, hay nói khác đi không quân hậu nào có để di chuyển theo quy tắc cờ vua. Mầu của các quân hậu không có ý nghĩa trong bài toán này. Như vậy, lời giải của bài toán là một cách xếp tám quân hậu trên bàn cờ sao cho không có hai quân nào đứng trên cùng hàng, hoặc cùng cột hoặc cùng đường chéo. Bài toán tám quân hậu có thể tổng quát hóa thành bài toán đặt n quân hậu trên bàn cờ n×n(n ≥ 4), bài toán không có nghiệm cho n=2,3. [wiki].

1.Một số ứng dụng

Bài toán giống như là một trò chơi, tuy nhiên đáng ngạc nhiên là có một số ứng dụng thực tế cho các vấn đề như cách tổ chứclưu trữ bộ nhớ song song, kiểm tra các mạch tích hợp lớn (VLSI - Very Large Scale Integration), kiểm soát tắc ngẽn giao thông, ngăn chặn deadlock. Vấn đề này cũng được áp dụng trong nhiều vấn đề thực tế mà các nghiệm liên quan tới sự hoán vị, trong đó có rất nhiều. Một trong những vấn đề như vậy là bài toán người du lịch (travelling salesperson problem). Bìa toán cũng được coi là một chương trình “hello world” của các bài toán thỏa mãn ràng buộc (Constraint Satisfaction Problem) [Norvig],...

2.Những giải thuật xung quanh bài toán

Điểm hấp dẫn của bài toán N-quân hậu là nó dễ dàng mô tả nhưng lại không dễ đề giải nó một cách hiệu quả. Kích cỡ nghiệm của không gian nghiệm có độ phức tạp hàm mũ NN. Đây là một sự bùng nổ về tổ hợp, gây khó khăn trong quá trình giải quyết.

Về mặt thuật toán, nếu tách riêng bài toán này, thì nó không thực sự quá quan trọng. Tuy nhiên, bài toán thường được coi như là một phép thử cho các phương pháp tối ưu - có rất nhiều các giải pháp cho vấn đề này trên trang web, nhưng chỉ có số ít là cho lời giải trong thời gian nhanh. Cũng chính vì sự lý thú của bài toán mà trong ngành khoa học máy tính nó được nghiên cứu rất đa dạng với nhiều thuật toán kỹ thuật tìm kiếm được sử dụng để tăng tốc độ cho bài toán: tìm kiếm quay lui (backtracking), nhánh cận (Branch and Bound), tìm kiếm theo chiều sâu với Heuristic [shel], thuật toán tiến hóa (Genetic Programming) [jes] hay dùng mạng nơron [jace]...

Hơn thế nữa, trong khi giải bài toán này, người ta còn gặp một loạt các vấn đề đã được toán học quan tâm từ lâu như hình vuông kỳ ảo (magic squares), hình vuông Latin (Latin squares)...

Có khoảng 320 bài viết về bài toán N-quân hậu, điều này đủ nói lên sự thu hút rất lớn của bài toán tưởng như nhỏ này.

Cũng trong quá trình giải người ta thấy rằng trong tất cả các nghiệm của bài toán có rất nhiều nghiệm “thừa” (có thể suy ra từ các nghiệm khác bằng các phép đối xứng, quay hay kết hợp cả hai), chính vì vậy người ta tìm cách loại bỏ nó để tăng hiệu quả chương trình (chúng tôi sẽ trở về vấn đề này trong một bài khác)

Cũng trong quá trình giải bài toán N-quân hậu, người ta cũng nghĩ ra một vài biến thể của bài toán: (i) tìm số quân hậu tối thiểu mà có thể khống chế tất cả các ô trong bàn cờ; (ii) bài toán 3-D N-quân hậu; (iii) Bài toán 9 quân hậu (được mở rộng thành bài toán N+K queens);(iv) Bài toán m quân hậu, m quân mã trên bàn cờ NxN (nếu có dịp chúng tôi cũng mong mở rộng thêm những vấn đề này).

Số nguyên tố vẫn luôn được coi là một loại số rất kỳ lạ, điều này lại được chứng minh một lần nữa trong bài toán N-quân hậu. Vơi N là số nguyên tố, sẽ có nghiệm với cách giải riêng cho bài toán (chúng tôi sẽ trở về vấn đề này trong một bài khác)

Với mong muốn bổ sung thêm những điều thú vị xung quanh bài toán này, chúng tôi sẽ viết một số bài về chủ đề này. Trong bài đầu tiên này, chúng tôi sẽ có những phần sau: 1. Lịch sử bài toán N-quân hậu

3.Lịch sử [wiki]

Bài toán được đưa ra vào 1848 bởi kỳ thủ Max Bezzel, và sau đó nhiều nhàtoán học , trong đó có Gauss và Georg Cantor, có các công trình về bài toán này và tổng quát nó thành bài toán xếp hậu. Các lời giải đầu tiên được đưa ra bởi Franz Nauck năm 1850. Nauck cũng đã tổng quát bài toán thành bài toán n quân hậu. Năm 1874, S. Gunther đưa ra phương pháp tìm lời giải bằng cách sử dụng định thức, và J.W.L. Glaisher hoàn chỉnh phương pháp này.

Edsger Dijkstra đã sử dụng vấn đề này năm 1972 để minh họa sức mạnh của những gì ông gọi là cấu trúc chương trình. Ông cũng mô tả chi tiết về thuật toán quay lui – theo chiều sâu.

Định lý: Với N > 3, có ít nhất một nghiệm cho bài toán N-quân hậu.

Định lý này được chứng minh lần đầu bới Ahrens năm 1910. Sau đó Hoffman, Loessi, và Moorenăm 1969. (Mathematics Magazine, March-April 1969, 66-72.)

Cách giải

1. Cách lưu trữ và giải bài toán

 

* Ta thấy khi đặt 1 quân hậu vào một ô ở hàng i cột j trên bàn cờ, nó sẽ chiếm dụng kiểm soát trên:

- Hàng ngang i.

- Cột dọc j.

- 1 Đường chéo song song với đường chéo chính.

- 1 Đường chéo song song với đường chéo phụ

* Nhận xét:

- Với đường chéo song song với đường chéo chính đi qua ô ở hàng i và cột j luôn có cùng hiệu (i-j).

- Với đường chéo song song với đường chéo phụ đi qua ô ở hàng i và cột j luôn có cùng tổng (i + j)

- Với một bàn cờ cỡ NxN ta có:

§ Chỉ số đường chéo chính chạy từ -(n-1)...(n-1)

§ Chỉ số đường chéo phụ chạy từ 2...2n

* Do vậy khi đặt quân hậu vào một ô ở hàng i và cột j chúng ta có thể dùng các mảng boolean để đánh dấu các hàng, cột mà nó chiếm dụng như:

- h[i] = true;// Hàng i đã bị chiếm.

- c[j] = true;// Cột j đã bị chiếm.

- cc[i-j] = true;// Chéo chính i - j đã bị chiếm

- cp[i+j] = true;// Chéo phụ i + j đã bị chiếm.

* Do vậy để đặt 1 quân hậu vào một ô ở hàng i, cột j bất kỳ chúng ta chỉ cần kiểm tra xem hàng i, cột j và hai đường chéo đã bị chiếm dụng chưa.

* Lần lượt đặt thử con hậu vào các vị trí:

- Đặt con hậu đầu tiên ở vị trí cột 1, hàng 1

- Nếu được đặt con hậu tiếp theo vào các ô ở cột tiếp sao cho không bị ăn cứ như vậy theo cho đến đến khi đủ số con hậu cần.

- Nếu không được quay lại bước trước và dịch chuyển quân hậu trước đó sang ô tiếp theo.

* Ví dụ với với n = 4 cách diễn tả tìm ra một nghiệm có thể diễn tả như sau:

 

 

2. Bằng đệ quy thử sai quay lui

Chúng ta xem mã chương trình

Procedure Try (i)

For j=1 to n do

If not h(j) And not c(i) And not cc(i-j) And not cp(i+j) then

{

solution(i)=j;

If i

c(i)=true;

h(j)= true;

cc(i-j)=true;

cp(i+j)=true;

try_col(i+1)

c(i)=false;

h(j)=false;

cc(i-j)=false;

cp(i+j)=false;

ELSE print_solution();

}

Thủ tục tìm tất cả các lời giải của bài toán n hậu chỉ bao gồm một lời gọi Try (1):Call Try_col(1);

3. Chương trình tham khảo (được cài đặt bằng Java)

3.1Giải bằng đệ quy thử sai quay lui:

NQueen.java

import java.util.*;

publicclass NQueen {

staticbooleanc [], h [],cc[], cp[];

staticintnx[],soCach = 0;

publicstaticvoid Try(int i){

for(int j = 1; j<=n; ++j){

if(!h[j] && !c[i] &&!cc[j-i+n]&&!cp[i+ j]){

x[i] = j;

if(i<n){

h[j] = true;

c[i] = true;

cc[j-i+n] = true;

cp[i + j] = true;

Try(i+1);

h[j] = false;

c[i] = false;

cc[j-i+n] = false;

cp[i + j] = false;

}else{

++soCach;

System.out.print("Cach " + soCach + ": ");

for(int l = 1; l<x.length; ++l)

System.out.print(x[l] + " ");

System.out.println();

}

}

}

}

publicstaticvoid main(String[] args) {

Scanner keyIn = new Scanner(System.in);

System.out.print("Nhap n = ");

n = keyIn.nextInt();

cnewboolean[n+1];

h = newboolean [n+1];

cc = newboolean[2*n + 1];//-n..n; 0 ..2n

cp =newboolean [2*n+1]; //2 .. 2n

x = newint [n+1];

Try(1);

}

}

3.2Giải bằng khử đệ quy:

Ở đây, chương trình dùng một Stack để lưu trữ các quân hậu được lưu lần lượt theo cột.

NQueenKDQ.java

import java.util.Scanner;

import java.util.Stack;

publicclass NQueenKDQ {

staticbooleanh[], cc[], cp[];

staticintnx[], soCach = 0;

static Stack sta;

staticvoid TimKQ() {

int cot = 1, hang = 1;

boolean boDatDuoc = false;

sta.push(hang);

while (true) {

// Duyet qua cac cot tim dap an

boDatDuoc= false;

if (cotn) {

for (int i = hang; in; ++i) {

// Duyet qua cac hang cua tung cot

if (!h[i] && !cc[i - cot + n] && !cp[i + cot]) {

x[cot] = i; //Dat quan hau vao cot, hang thu i

h[i] = true;

boDatDuoc = true;

cc[i - cot + n] = true;

cp[i + cot] = true;

sta.push(i);

hang = 1;

cot += 1; // Chuyen sang cot tiep theo

break;

}

}

else {

++soCach;

System.out.print("Cach " + soCach + ": ");

for(int l = 1; l<x.length; ++l)

System.out.print(x[l] + " ");

System.out.println();

}

if(!boDatDuoc){

//Quay lui

cot -=1;

hang = sta.pop();

h[hang] = false;

cc[hang - cot + n] = false;

cp[hang + cot] = false;

hang +=1;

}

if(cot ==1 && hang>n){

break;

}

}

}

publicstaticvoid main(String[] args) {

Scanner keyIn = new Scanner(System.in);

System.out.print("Nhap n = ");

n = keyIn.nextInt();

h = newboolean[n + 1];

cc = newboolean[2 * n + 1];// -n..n; 0 ..2n

cp = newboolean[2 * n + 1]; // 2 .. 2n

x = newint[n + 1];

sta = new Stack();

TimKQ();

}

}

 Theo Tin học và nhà trường