1. 程式人生 > >演算法(一)——回溯法

演算法(一)——回溯法

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

      回溯演算法的基本思想是:從一條路往前走,能進則進,不能進則退回來,換一條路再試。

N皇后問題

【描述】

      在n×n格的棋盤上放置彼此不受攻擊的n個皇后。按照國際象棋的規則,皇后可以攻擊與之處在同一行或同一列或同一斜線上的棋子。n後問題等價於再n×n的棋盤上放置n個皇后,任何2個皇后不妨在同一行或同一列或同一斜線上。

【分析】

      要解決N皇后問題,其實就是要解決好怎麼放置這n個皇后,每一個皇后與前面的所有皇后不能在同一行、同一列、同一對角線,在這裡我們可以以行優先,就是說皇后的行號按順序遞增,只考慮第i個皇后放置在第i行的哪一列,所以在放置第i個皇后的時候,可以從第1列判斷起,如果可以放置在第1個位置,則跳到下一行放置下一個皇后。如果不能,則跳到下一列...直到最後一列,如果最後一列也不能放置,則說明此時放置方法出錯,則回到上一個皇后向之前放置的下一列重新放置。此即是回溯法的精髓所在。當第n個皇后放置成功後,即得到一個可行解,此時再回到上一個皇后重新放置尋找下一個可行解...如此後,即可找出一個n皇后問題的所有可行解。


迭代程式碼

不在同一對角線上:

(1)兩個座標之和相等(2)兩個座標之差相等。例如有兩個點作為分別為(a,b)和(c,d),他們在同一對角線上的條件是(1)a+b=c+d (2) a-b=c-d    等價於   |a-b|=|c-d|.

int Place(int *Column,int index){
	int i;
	for(i=1;i<index;i++){
	     int Column_differ=abs(Column[index] – Column[i]);
	     int Row_differ=abs(index - i);
	     if(Column[i] == Column[index] || Column_differ == Row_differ)/*有皇后與其在同列或同一斜線上*/
		return 0;
        }
        return 1; /*沒有皇后與其同行、同列或同對角線*/
}

void N_Queue(int n){
	int Column[n + 1];  //<span style="font-size: 18.18181800842285px;">Column[i]=a   代表把皇后存放在第i行的第a個位置。</span>
	<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">int </span>index=1;          //行數
	int i;               //迴圈變數
	int answer_num=0;    //解個數
	for(I =1;i <= n;i++)    //初始化陣列Column
             Column[i]=0;
	while(index > 0){
	     Column[index]++;
	     while(Column[index] <= n && !Place(Column[index],index))   /*尋找皇后的位置*/
	         Column[index]++;
	     if(Column[index] <= n){
	         if(index== n){        //如果是最後一行時,即有一個解時
	             answer_num++;     
		     for(i = 1;i <= n;i++)
		         Column[index]++;
                  }
                  else{           /*繼續尋找下一個皇后*/
		     index++;	
		     Column[index]=0;
                  }
              }
              else
	         index--;         /*當前皇后無法放置,回溯至上一個皇后*/
       }
}
</span>
遞迴程式碼
int queen(int index)   
{   
    if(index>n && n>0) //當放置的皇后超過n時,可行解個數加1,此時n必須大於0   
        answer_sum++;   
    else  
      for(int i=1;i<=n;i++)   
      {   
          Column[index] = i; //標明第t個皇后放在第i列   
          if(place(index)) //如果可以放在某一位置,則繼續放下一皇后   
             queen(index+1);    
      }   
    return sum;   
}