1. 程式人生 > >回溯演算法理解

回溯演算法理解

一、演算法含義

回溯演算法也叫試探法,它是一種系統地搜尋問題的解的方法。回溯演算法的基本思路是:暴力演算法的改進,在通過遍歷所有路徑基礎上,通過回溯(往回找)篩除不可能的路徑,提高效率。

二、解題步驟:

1.確定一個解空間,它包含問題的解;
2.利用適於搜尋的方法組織解空間;
3.利用深度優先法搜尋解空間;
4.利用剪枝(約束函式、限界函式)避免移動到不可能產生解的子空間。

三、演算法框架 

 

bool constraint(int t){};//約束函式
bool bound(int t){};//限界函式

void backtrack(int t){   
  
if(t > n) output(x); else{ for(int i = f(n,t); i <= g(n,t);i++){ //該節點的子節點(分量的所有下一個分量)
    x[t] = h(i);
    if(constraint(t) && bound(t))
      backtrack(t+1); }
    }
}

 

四、例題

7-1 子集和問題 (50 分)

設集合S={x1,x2,…,xn}是一個正整數集合,c是一個正整數,子集和問題判定是否存在S的一個子集S1,使S1中的元素之和為c。試設計一個解子集和問題的回溯法。

輸入格式:

輸入資料第1行有2個正整數n和c,n表示S的大小,c是子集和的目標值。接下來的1行中,有n個正整數,表示集合S中的元素。 是子集和的目標值。接下來的1 行中,有n個正整數,表示集合S中的元素。

輸出格式:

輸出子集和問題的解,以空格分隔,最後一個輸出的後面有空格。當問題無解時,輸出“No Solution!”。

輸入樣例:

5 10
2 2 6 5 4

輸出樣例:

2 2 6 

程式碼:

#include <iostream>
using namespace std;
int flag =0;
int s[100000];
int selec[100000
]; int fin_selec[100000]; void backTrack(int target,int t,int sum ,int n){ if(flag==1)return; if (t>=n) { if (sum == target) { for (int i=0; i<n; i++) { fin_selec[i] = selec[i]; } flag = 1; return; } return; } if (sum+s[t]<=target) { selec[t]=1; sum +=s[t]; backTrack(target, t+1, sum, n); selec[t]=0; sum -= s[t]; } selec[t] =0; backTrack(target, t+1, sum, n); } int main(){ int n,target; cin>>n>>target; for (int i=0; i<n; i++) { cin>>s[i]; selec[i]=0; fin_selec[i]=0; } int sum=0; for (int i=0; i<n; i++) { sum+=s[i]; } if (sum<target) { cout<<"No Solution!"<<endl; exit(0); } backTrack(target, 0, 0, n); if (flag==1) { for (int i=0; i<n; i++) { // cout<<fin_selec[i]; if (fin_selec[i]==1) { cout<<s[i]<<" "; } } }else cout<<"No Solution!"<<endl; return 0; }

 

五、總結

由於對演算法的不夠熟悉,導致細節出問題,思維不夠發散,模版很好用,再加上對約束函式限界函式的完善就是整道題的清晰思路。