算法入門經典-第七章 例題7-4-1 拓展 n皇后問題 回溯法


實際上回溯法有暴力破解的意思在里面,解決一個問題,一路走到底,路無法通,返回尋找另   一條路。

回溯法可以解決很多的問題,如:N皇后問題和迷宮問題。

一.概念

回溯算法實際類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解,當發現不滿足條件的時候,就回溯返回,嘗試別的路徑。

百度解釋:回溯法(探索與回溯法)是一種選優搜索法,又稱為試探法,按選優條件向前搜索,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法,而滿足回溯條件的某個狀態的點稱為“回溯點”。

二.基本思想

在包含問題的所有解的解空間樹中,按照深度優先搜索的策略,從根結點出發深度探索解空間樹。當探索到某一結點時,要先判斷該結點是否包含問題的解,如果包含,就從該結點出發繼續探索下去,如果該結點不包含問題的解,則逐層向其祖先結點回溯。(其實回溯法就是對隱式圖的深度優先搜索算法)。

 若用回溯法求問題的所有解時,要回溯到根,且根結點的所有可行的子樹都要已被搜索遍才結束。

 而若使用回溯法求任一個解時,只要搜索到問題的一個解就可以結束。

 

三.n皇后問題

////N皇后是典型DPS問題,這里是用遞歸實現的,要想輸出必須要存儲上級運算結果。 
#include<iostream>  
#include<cstdio>  
#include<cstring>  
#include<cstdlib>  
#include<string>  
#include<cctype>  
#include<cmath>  
#include<map>  
#include<set>  
#include<vector>  
#include<queue>  
#include<stack>  
#include<ctime>  
#include<algorithm>  
#include<climits>  
using namespace std;  
const int N=101;  
   static int disp[16];
int C[N];  
int tot;  
int n;  
void search(int cur)
{

    if(cur==n){
            for( int i = 0; i<n; i++ )
   printf( "%d " , disp[i] );
   printf("\n");
   tot++;
   }
    else
     for(int i=0;i<n;i++)
    {
        int ok=1;
        C[cur]=i;//嘗試把cur行的皇后放在第i列 
        for(int j=0;j<cur;j++)//檢查是否和前面的皇后沖突
        if(C[cur]==C[j]||cur-C[cur]==j-C[j]||cur+C[cur]==j+C[j])
        {
            ok=0;break;
        }
        
    
    if(ok) {
          disp[cur]=i;//當前行的皇后在第幾列 
                search(cur+1); 
                } 
} 
}
int main()  
{  
    while(cin>>n)  
    {  
        tot=0;  
        search(0);  
        cout<<tot<<"種方法"<<endl;  
    }  
    return 0;  
}   

 

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
int c[150],vis[3][150],tot,n=8,sum_max;
int mapn[9][9];
void search(int cur)
{
    if(cur==n)//遞歸邊界,只要走到了這里,所有皇后必然不沖突
    {
        if(sum_max<tot)
            sum_max = tot;
    }
    else for(int i=0;i<n;i++)
    {
        if(!vis[0][i]&&!vis[1][cur+i]&&!vis[2][cur-i+n])//利用二維數組直接判斷
        {//0為豎行,1為副對角線,2為主對角線
            c[cur] = i;//保存下每行皇后的位置
            tot += mapn[cur][i];
            vis[0][i] = vis[1][cur+i] = vis[2][cur-i+n] = 1;
            search(cur+1);
            vis[0][i] = vis[1][cur+i] = vis[2][cur-i+n] = 0;//記得改回來
            tot -= mapn[cur][i];
        }
    }
}
int main()
{
    int T;
    cin >> T;
    while(T--)
    {
        sum_max = 0,tot = 0;
        memset(vis,0,sizeof(vis));
        for(int i=0;i<8;i++)
            for(int j=0;j<8;j++)
            {
                cin >> mapn[i][j];
            }
        search(0);
        printf("%5d\n",sum_max);
    }
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM