八皇后问题
2016-10-28 11:26
127 查看
1.什么是八皇后问题?
八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n。而且仅当 n = 1 或 n ≥ 4 时问题有解。
八皇后问题最早是由国际西洋棋棋手马克斯·贝瑟尔于1848年提出。之后陆续有数学家对其进行研究,其中包括高斯和康托,并且将其推广为更一般的n皇后摆放问题。八皇后问题的第一个解是在1850年由弗朗兹·诺克给出的。诺克也是首先将问题推广到更一般的n皇后摆放问题的人之一。1874年,S.冈德尔提出了一个通过行列式来求解的方法,这个方法后来又被J.W.L.格莱舍加以改进。
艾兹格·迪杰斯特拉在1972年用这个问题为例来说明他所谓结构性编程的能力。
八皇后问题出现在1990年代初期的著名电子游戏第七访客中。
![](https://img-blog.csdn.net/20161028105854141?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
2.求解思路:
问题比较显而易见的是,一共要放置8个皇后.每行放置一个,在每一行放置皇后时,初始有8个位置可以放置。但是由于前面已经放置皇后的限制,要在8个位置上寻找到可以放置的位置。直到8行均找到放置位置,问题有一个解。在某一行如果无法找到放置位置,需要回溯到上一行,在上一行已经找到位置的基础上寻找下一个可以放置的位置,继续进行这个过程。如果要找到所有可行解,在找到第一个解后,继续需找最后一行的下一个可以放置位置。直到回溯到第一行无法找到可以放置位置,即找到全部解。
3.非递归实现:
伪代码:
1.初始化一个二维数组,每个位置置0,放置皇后置1.
2.依次对每一行寻找放置皇后的位置,如果可以放置,将位置置1,继续下一行;否则,回溯到上一行的下一个位置
进行判断,并将上一个可以放置位置置0.重复此过程,直到所有行均有可放置位置.打印一组解.
3.找到一组解后,试图在最后一行下个位置寻找解,直到回溯到第一行也没有可以放置位置.即找到所有解.
4000
br />
八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n。而且仅当 n = 1 或 n ≥ 4 时问题有解。
八皇后问题最早是由国际西洋棋棋手马克斯·贝瑟尔于1848年提出。之后陆续有数学家对其进行研究,其中包括高斯和康托,并且将其推广为更一般的n皇后摆放问题。八皇后问题的第一个解是在1850年由弗朗兹·诺克给出的。诺克也是首先将问题推广到更一般的n皇后摆放问题的人之一。1874年,S.冈德尔提出了一个通过行列式来求解的方法,这个方法后来又被J.W.L.格莱舍加以改进。
艾兹格·迪杰斯特拉在1972年用这个问题为例来说明他所谓结构性编程的能力。
八皇后问题出现在1990年代初期的著名电子游戏第七访客中。
2.求解思路:
问题比较显而易见的是,一共要放置8个皇后.每行放置一个,在每一行放置皇后时,初始有8个位置可以放置。但是由于前面已经放置皇后的限制,要在8个位置上寻找到可以放置的位置。直到8行均找到放置位置,问题有一个解。在某一行如果无法找到放置位置,需要回溯到上一行,在上一行已经找到位置的基础上寻找下一个可以放置的位置,继续进行这个过程。如果要找到所有可行解,在找到第一个解后,继续需找最后一行的下一个可以放置位置。直到回溯到第一行无法找到可以放置位置,即找到全部解。
3.非递归实现:
伪代码:
1.初始化一个二维数组,每个位置置0,放置皇后置1.
2.依次对每一行寻找放置皇后的位置,如果可以放置,将位置置1,继续下一行;否则,回溯到上一行的下一个位置
进行判断,并将上一个可以放置位置置0.重复此过程,直到所有行均有可放置位置.打印一组解.
3.找到一组解后,试图在最后一行下个位置寻找解,直到回溯到第一行也没有可以放置位置.即找到所有解.
struct point { int x; int y; }; int Eight[][8] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0};
bool Put(int array[][8], point pt) { for (int i = 0; i<8; i++) // 横坐标 { for (int j = 0; j<8; j++) // 纵坐标 { if (array[i][j] == 1 ) // 如果当前坐标有皇后,根据此点判断传入点是否可以放置 { if(pt.x == i || pt.y == j) // 判断是否在同一行或者同一列 return false; // 每个点四个方向 // 左上 /*int m = i; int n = j; while ((--m>=0) && (--n >=0)) { if (pt.x == m && pt.y == n) { return false; } } // 右上 m = i; n = j; while ((--m>=0) && (++n) <= 7) { if (pt.x == m && pt.y == n) { return false; } }*/ // 左下 int m = i; int n = j; while ((++m <= 7) && (--n >= 0)) { if (pt.x == m && pt.y == n) { return false; } } // 右下 m = i; n = j; while (++m<=7 && ++n <= 7) { if (pt.x == m && pt.y == n) { return false; } } } } } return true; }
// 打印八皇后的解 void Print() { for (int m = 0; m<8; m++) { for (int n = 0; n<8; n++) { printf("%d, ", Eight[m] ); } printf("\r\n"); } }
int nCount = 0; for(int i = 0; i<8; i++) { bool bFind = false; // 标识当前行是否找到解 int j = 0; // 每次寻找插入位置时,判断是否当前行已经有放置皇后的位置,如果有 // 需要从下一个位置开始寻找,并将原位置置0 for (int k = 0; k<8; k++) { if (Eight[i][k] == 1) { j = k + 1; Eight[i][k] = 0; break; } } for (j; j<8; j++) { point pt; pt.x = i; pt.y = j; if(Put(Eight, pt)) // 如果找到了可以放置的坐标,寻找下一行 { bFind = true; Eight[pt.x][pt.y] = 1; break; }else { continue; } } if (bFind) // 不用回溯 { if (i == 7) // 找到一种解法 { nCount++; Print(); i--;//试图找到下一种解法 printf("%d\r\n", nCount); //getchar(); } }else // 回溯到上一层 { i -= 2; if(i < -1) { printf("over"); getchar(); } } }4.递归实现
static int gEightQueen[8] = { 0 }, gCount = 0; void print()//输出每一种情况下棋盘中皇后的摆放情况 { for (int i = 0; i < 8; i++) { int inner; for (inner = 0; inner < gEightQueen[i]; inner++) cout << "-"; cout <<"#"; for (inner = gEightQueen[i] + 1; inner < 8; inner++) cout << "-"; cout<<endl; } cout << "==========================\n"; } /* loop表示在第几行放置, value当前放置的位置 0表示当前位置不可用,1表示当前位置可以放置*/ int check_pos_valid(int loop, int value)//检查是否存在有多个皇后在同一行/列/对角线的情况 { int index; int data; for (index = 0; index < loop; index++) // 对前面每个元素的位置进行判断,看是否符合要求 { data = gEightQueen[index]; if (value == data) // 同一列 return 0; if ((index + data) == (loop + value)) // 左下对角线 return 0; if ((index - data) == (loop - value)) // 右下对角线 return 0; } return 1; } void eight_queen(int index) { int loop; for (loop = 0; loop < 8; loop++) // 对8个位置进行判断 { if (check_pos_valid(index, loop)) { gEightQueen[index] = loop; if (7 == index) { gCount++, print(); gEightQueen[index] = 0; // 将当前位置置0,试图寻找下一个解 return; } eight_queen(index + 1); // 没有找到,上面返回,将上一层置0,重新寻找 gEightQueen[index] = 0; } } }<
4000
br />