QTableView載入百萬條資料佔用記憶體少
阿新 • • 發佈:2020-11-27
問題概述:
八皇后問題,是指在8x8的國際象棋棋盤上放置8個皇后,保證任意兩個皇后都無法互相攻擊的問題。皇后的攻擊範圍為:上下左右斜對角線都可以攻擊到。示意圖如下:現在,有一個這樣的問題:現在已經在棋盤上擺放了k個皇后,且這k個皇后的格子位置已經給出。請編寫一個程式,根據給出的k個有皇后的格子,輸出已擺放8個皇后的國際象棋棋盤。(請注意:這題有唯一解!)
輸入例項:
2
2 2
5 3
輸出例項:
......Q.
Q.......
..Q.....
.......Q
.....Q..
...Q....
.Q......
....Q...
解題思路:
這道題是回溯法的經典問題,一般的思路是:在第一行的任意位置擺放第一個皇后,接著在第二行且不會被其他皇后攻擊的任意位置擺放第二個皇后..... 直到皇后擺放完畢。因此,我們需要使用遞迴的方式來依次完成八個皇后的擺放。並且使用4個數組來存放行、列、左對角線、右對角線是否處於皇后的攻擊範圍內。依次如下:(注意:在這裡由於是8x8的棋盤,所以這裡N為8)
- row[N] 如果row[N]不為空,則x行受到攻擊
- col[N] 如果col[N]不為空,則x列受到攻擊
- dpos[2N-1] 如果dpos[2N-1]不為空,則斜向左下的x列受到攻擊
- dneg[2N-1] 如果dneg[2N-1]不為空,則斜向右下的x列受到攻擊
既然這些陣列有了,那麼我們怎樣在擺放皇后的時候,去設定皇后的攻擊範圍呢?這裡給出推導的一個公式:
- row[i] i 的範圍為 0-7 代表皇后攻擊的範圍為第i行
- col[j] j 的範圍為 0-7 代表皇后攻擊的範圍為第j列
- dpos[i+j] i+j 的範圍為 0-14 代表皇后攻擊的範圍為斜向左下的i+j列
- dneg[(i-j)+(N-1)] (i-j)+(N-1)的範圍為 0-14 代表皇后攻擊的範圍為斜向右下的(i-j)+(N-1)列
只要row[i],col[j],dpos[i+j],dneg[(i-j)+(N-1)]中有任意一個不為空,格子(i,j)就會收到攻擊。也就是說,當row[i],col[j],dpos[i+j],dneg[(i-j)+(N-1)]全部都為空時,皇后才能放置在(i,j)格子中。
其中dpos和dneg陣列的範圍為0-14,共有15條斜線。(如果你要疑問為什麼為15條,可以自行去畫一下圖,列出所有的左斜線和右斜線。數個數去看一下。)
但是,這道題有一個限定條件就是有些皇后事先已經擺放好了,所以如果我們要是直接進行遞迴的話,是無法進行遞迴的。(例如:有個皇后的位置為:(2,2)。那麼,當你一行一行的進行遞迴時,由於第二行已經有了皇后。那麼,第二行就無法擺放棋子。所以,就導致了無法遞迴的現象出現。
所以,我們應該如何避免這個問題呢?在這裡給出思路:我們首先將已經擺放好的皇后做出標記。在之後,可以將所有八個皇后的擺放方式遞迴出來,然後根據已經擺放好的皇后標記,從所有八個皇后的擺放方式中篩選帶有事先擺放好的皇后的情況。最後輸出即可。(可能這段話讓人難以理解。(難以理解的話,就閱讀一下程式碼吧!))
程式碼如下:
#include <iostream>
#include <cstdio>
using namespace std;
bool Graph[8][8]; //定義一個8x8的棋盤(圖)
int row[8]; //代表是否受到攻擊的行(初始化均為0,代表沒有受到攻擊,為1代表受到攻擊)
int col[8]; //代表是否受到攻擊的列
int dpos[15]; //代表是否受到攻擊的左對角線
int dneg[15]; //代表是否受到攻擊的右對角線
void dfs(int deep); //代表深度優先搜尋(回溯)的函式,deep代表搜尋的深度
int k, h, w; //代表皇后的個數,以及皇后的所在的行列座標
void dfs(int deep) //通過dfs,來檢索出所有擺放八皇后的情況
{
int i, j;
if (deep == 8) //代表八個皇后全部放置完成
{
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
if (Graph[i][j]) //如果當前位置有事先設定好的皇后的話
{
if (row[i] != j) //如果當前的擺放情況不滿足事先給定好的情況的話。(由於,這道題有部分皇后是提前擺好的,所以我們需要搜尋出所有擺放好的八皇后的情況,從中篩選出提前擺好的情況)
{
return; //不滿足情況的話,直接進行退出
}
}
}
}
for (i = 0; i < 8; i++) //如果擺放情況滿足於事先給定好的情況的話就輸出棋盤。
{
for (j = 0; j < 8; j++)
{
if (row[i] == j)
{
printf("Q");
}
else
{
printf(".");
}
}
cout << endl;
}
return;
}
for (i = 0; i < 8; i++) //搜尋當前行中的列
{
if (row[deep] == 0 && col[i] == 0 && dpos[deep+i] == 0 && dneg[(deep-i)+(8-1)] == 0) //如果當前行中的列不是處於皇后的行、列、左對角線、右對角線的攻擊範圍內
{
row[deep] = i; //放置皇后
col[i] = 1;
dpos[deep + i] = 1;
dneg[(deep - i) + (8 - 1)] = 1;
dfs(deep + 1); //在下一行中繼續搜尋
row[deep] = 0; //把原先放置皇后的所有操作進行還原(回溯操作)
col[i] = 0;
dpos[deep + i] = 0;
dneg[(deep - i) + (8 - 1)] = 0;
}
}
return; //代表如果當前行中無法放置皇后的話,那麼就回溯到上一層重新找列放置皇后
}
int main()
{
int i,j;
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
Graph[i][j] = false; //代表初始化棋盤
}
}
scanf("%d", &k);
for (i = 0; i < k; i++)
{
scanf("%d %d", &h, &w);
Graph[h][w] = true; //放置事先設定好的皇后
}
dfs(0); //代表進行搜尋
}