C#用遞歸算法解決八皇后問題
1.引子
中國有一句古話,叫做“不撞南墻不回頭",生動(dòng)的說明了一個(gè)人的固執(zhí),有點(diǎn)貶義,但是在軟件編程中,這種思路確是一種解決問題最簡(jiǎn)單的算法,它通過一種類似于蠻干的思路,一步一步地往前走,每走一步都更靠近目標(biāo)結(jié)果一些,直到遇到障礙物,我們才考慮往回走。然后再繼續(xù)嘗試向前。通過這樣的波浪式前進(jìn)方法,最終達(dá)到目的地。當(dāng)然整個(gè)過程需要很多往返,這樣的前進(jìn)方式,效率比較低下。
2.適用范圍
適用于那些不存在簡(jiǎn)明的數(shù)學(xué)模型以闡明問題的本質(zhì),或者存在數(shù)學(xué)模型,但是難于實(shí)現(xiàn)的問題。
3.應(yīng)用場(chǎng)景
在8*8國際象棋棋盤上,要求在每一行放置一個(gè)皇后,且能做到在豎方向,斜方向都沒有沖突。國際象棋的棋盤如下圖所示:
4.分析
基本思路如上面分析一致,我們采用逐步試探的方式,先從一個(gè)方向往前走,能進(jìn)則進(jìn),不能進(jìn)則退,嘗試另外的路徑。首先我們來分析一下國際象棋的規(guī)則,這些規(guī)則能夠限制我們的前進(jìn),也就是我們前進(jìn)途中的障礙物。一個(gè)皇后q(x,y)能被滿足以下條件的皇后q(row,col)吃掉
1)x=row(在縱向不能有兩個(gè)皇后)
2)y=col(橫向)
3)col + row = y+x;(斜向正方向)
4)col - row = y-x;(斜向反方向)
遇到上述問題之一的時(shí)候,說明我們已經(jīng)遇到了障礙,不能繼續(xù)向前了。我們需要退回來,嘗試其他路徑。
我們將棋盤看作是一個(gè)8*8的數(shù)組,這樣可以使用一種蠻干的思路去解決這個(gè)問題,這樣我們就是在8*8=64個(gè)格子中取出8個(gè)的組合,C(64,80) = 4426165368,顯然這個(gè)數(shù)非常大,在蠻干的基礎(chǔ)上我們可以增加回溯,從第0列開始,我們逐列進(jìn)行,從第0行到第7行找到一個(gè)不受任何已經(jīng)現(xiàn)有皇后攻擊的位置,而第五列,我們會(huì)發(fā)現(xiàn)找不到皇后的安全位置了,前面四列的擺放如下:
第五列的時(shí)候,擺放任何行都會(huì)上圖所示已經(jīng)存在的皇后的攻擊,這時(shí)候我們認(rèn)為我們撞了南墻了,是回頭的時(shí)候了,我們后退一列,將原來擺放在第四列的皇后(3,4)拿走,從(3,4)這個(gè)位置開始,我們?cè)俚谒牧兄袑ふ蚁乱粋€(gè)安全位置為(7,4),再繼續(xù)到第五列,發(fā)現(xiàn)第五列仍然沒有安全位置,回溯到第四列,此時(shí)第四列也是一個(gè)死胡同了,我們?cè)倩厮莸降谌?,這樣前進(jìn)幾步,回退一步,最終直到在第8列上找到一個(gè)安全位置(成功)或者第一列已經(jīng)是死胡同,但是第8列仍然沒有找到安全位置為止
總結(jié)一下,用回溯的方法解決8皇后問題的步驟為:
1)從第一列開始,為皇后找到安全位置,然后跳到下一列
2)如果在第n列出現(xiàn)死胡同,如果該列為第一列,棋局失敗,否則后退到上一列,在進(jìn)行回溯
3)如果在第8列上找到了安全位置,則棋局成功。
8個(gè)皇后都找到了安全位置代表棋局的成功,用一個(gè)長(zhǎng)度為8的整數(shù)數(shù)組queenList代表成功擺放的8個(gè)皇后,數(shù)組索引代表棋盤的col向量,而數(shù)組的值為棋盤的row向
量,所以(row,col)的皇后可以表示為(queenList[col],col),如上圖中的幾個(gè)皇后可表示為:
queenList[0] = 0; queenList[1] = 3; queenList[2] = 1; queenList[3] = 4; queenList = 2;
我們看一下如何設(shè)計(jì)程序:
首先判斷(row,col)是否是安全位置的算法:
bool IsSafe(int col,int row,int[] queenList)
{
//只檢查前面的列
for (int tempCol = 0; tempCol < col; tempCol++)
{
int tempRow = queenList[tempCol];
if (tempRow == row)
{
//同一行
return false;
}
if (tempCol == col)
{
//同一列
return false;
}
if (tempRow - tempCol == row - col || tempRow + tempCol == row + col)
{
return false;
}
}
return true;
}
設(shè)定一個(gè)函數(shù),用于查找col列后的皇后擺放方法:
/// <summary>
/// 在第col列尋找安全的row值
/// </summary>
/// <param name="queenList"></param>
/// <param name="col"></param>
/// <returns></returns>
public bool PlaceQueue(int[] queenList, int col)
{
int row = 0;
bool foundSafePos = false;
if (col == 8) //結(jié)束標(biāo)志
{
//當(dāng)處理完第8列的完成
foundSafePos = true;
}
else
{
while (row < 8 && !foundSafePos)
{
if (IsSafe(col, row, queenList))
{
//找到安全位置
queenList[col] = row;
//找下一列的安全位置
foundSafePos = PlaceQueue(queenList, col + 1);
if (!foundSafePos)
{
row++;
}
}
else
{
row++;
}
}
}
return foundSafePos;
}
調(diào)用方法:
static void Main(string[] args)
{
EightQueen eq = new EightQueen();
int[] queenList = new int[8];
for (int j = 0; j < 8; j++)
{
Console.WriteLine("-----------------"+j+"---------------------");
queenList[0] = j;
bool res = eq.PlaceQueue(queenList, 1);
if (res)
{
Console.Write(" ");
for (int i = 0; i < 8; i++)
{
Console.Write(" " + i.ToString() + " ");
}
Console.WriteLine("");
for (int i = 0; i < 8; i++)
{
Console.Write(" "+i.ToString()+" ");
for (int a = 0; a < 8; a++)
{
if (i == queenList[a])
{
Console.Write(" q ");
}
else
{
Console.Write(" * ");
}
}
Console.WriteLine("");
}
Console.WriteLine("---------------------------------------");
}
else
{
Console.WriteLine("不能完成棋局,棋局失??!");
}
}
Console.Read();
}
遞歸算法PlaceQueue,完成這樣的功能:它尋找第col列后的皇后的安全擺放位置,如果該函數(shù)返回了false,表示當(dāng)前進(jìn)入了死胡同,需要進(jìn)行回溯,直到為0-7列都找
到了安全位置或者找遍這些列都找不到安全位置的時(shí)候終止。
用遞歸算法解決8皇后問題的示例程序:
http://xiazai.jb51.net/201606/yuanma/EightQueens(jb51.net).rar
上一篇:C#實(shí)現(xiàn)的xml操作類完整實(shí)例
欄 目:C#教程
本文標(biāo)題:C#用遞歸算法解決八皇后問題
本文地址:http://www.jygsgssxh.com/a1/C_jiaocheng/6421.html
您可能感興趣的文章
- 01-10C#實(shí)現(xiàn)判斷當(dāng)前操作用戶管理角色的方法
- 01-10C#使用Dispose模式實(shí)現(xiàn)手動(dòng)對(duì)資源的釋放
- 01-10C#3.0使用EventLog類寫Windows事件日志的方法
- 01-10C#調(diào)用dos窗口獲取相關(guān)信息的方法
- 01-10C#中DataGridView常用操作實(shí)例小結(jié)
- 01-10C#實(shí)現(xiàn)讀取被進(jìn)程占用的文件實(shí)現(xiàn)方法
- 01-10C#禁用雙擊窗體圖標(biāo)關(guān)閉窗體的方法
- 01-10C#使用windows服務(wù)開啟應(yīng)用程序的方法
- 01-10C#線程隊(duì)列用法實(shí)例分析
- 01-10C#利用反射技術(shù)實(shí)現(xiàn)去掉按鈕選中時(shí)的邊框效果


閱讀排行
- 1C語言 while語句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語言實(shí)現(xiàn)“百馬百擔(dān)”問題方法
- 4C語言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
- 01-10WinForm實(shí)現(xiàn)仿視頻播放器左下角滾動(dòng)新
- 01-10C#停止線程的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實(shí)現(xiàn)讀取注冊(cè)表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 04-02jquery與jsp,用jquery
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10C#中split用法實(shí)例總結(jié)
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10delphi制作wav文件的方法
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子


