求解步驟
1,定義給定問題的解向量解空間【子集樹/排列樹】
2,設計剪支函式【限界函式及約束函式】
3,深度優先遍歷結合剪支得出解
求解過程
1,是否為完全解,是則輸出;
2,是否為部分解,是則進行下乙個解分量的判斷;
3,是否為當前可選集合中的最後乙個元素,是則回溯,重新判斷上乙個節點,否則判斷可選集合中的下乙個元素
注:若上乙個節點擊擇的是上乙個可選集合中的最後乙個元素,則再次回溯。
練習一:求解部分和問題
題目內容:
給出n個正整數組成的陣列a,求能否從中選出若干個,使他們的和為k。如果可以,輸出:「yes」,否則輸出"no"。
輸入格式:
第1行:2個數n、k, n為陣列的長度, k為需要判斷的和(2 ≤n ≤ 20,1 ≤ k ≤ 10^9)
第2 到第 n + 1行:每行1個數,對應陣列的元素a[i] (1 ≤ a[i]≤ 10^6)
輸出格式:
如果可以,輸出:「yes」,否則輸出"no"。
樣例輸入
4 1312
47樣例輸出
yes演算法描述【非遞迴】
輸入:需要判斷的和k,陣列長度n,陣列元素
輸出:判斷結果yes/no
1,初始化狀態向量result[i]=-1;[-1未初始狀態,0表示選入,1表示不選入,2表示已無可選情況]
2,num=0;
3,while(num>=0)
3.1result[num]++,判斷該元素下一狀態是否可行;
3.2若該狀態可行,則轉步驟3.3;若發生衝突,則result[num]++試探下一狀態;
3.3若判斷函式返回成功標誌,輸出yes,結束演算法;
3.4若num=2,即已無可選狀態時,重置num的狀態,num–,回溯至其根結點判斷其狀態。
4,判斷所有狀態皆無成功結果,輸出no,演算法結束。
c++實現
#includeusing namespace std;
int n, k;
int number[20];
int *result=new int[n];
int check(int num)
if (sum < k)
if (sum == k)return 2;
else return 0;
}int main()
int num = 0;
while (num >= 0)
if (temp==2)
if (num < n-1&&result[num]<2)num++;//進行下一階段的判斷
if(result[num]>=2)
result[num--] = -1;//重置num狀態,回溯到上一節點
} cout << "no";//無可選搭配
return 0;
}
注意
1,需有輸出結果,判斷是否重置回溯的時候需用if判斷是否執行,而非直接else【漏掉對no情況的判斷】;
2,發生衝突時,result[num]++一次即可,避免遺漏對於元素處於不加入狀態的情況;
3,直接在while迴圈結束後進行失敗標誌的輸出即可。
4,對於和的判斷,每次判斷時在函式中根據標誌狀態計算,避免回溯時對sum的計算複雜。
練習2求解最小機器重量設計問題
題目內容:
設某一機器由n個部件組成,部件編號為1-n,每一種部件都可以從m個不同的**商處購得,**商編號為1~m。設wij是從**商j處購得的部件i的重量,cij是相應的**。對於給定的機器部件重量和機器部件**,計算總**不超過d的最小重量機器設計。(注意:輸出結果中第一行最後沒有空格。比如下面的輸出樣例中1 3 1後面沒有空格。)
輸入格式:
第1行輸入3個正整數n,m和d。接下來n行輸入wij(每行m個整數),最後n行輸入cij(每行m個整數),這裡1≤n、m≤100。
輸出格式:
輸出的第1行包括n個整數,表示每個對應的**商編號,第2行為對應的最小重量。
輸入樣例:
3 3 7
1 2 3
3 2 1
2 3 2
1 2 3
5 4 2
2 1 2
輸出樣例:
1 3 1
4演算法描述
矩陣weight[i][j]儲存**商j部件i的重量,value[i][j]儲存**,result[i]儲存部件i所選**商,r[i]為最終結果
輸入:部件數n,**商m,最大**d,各**商所提供不同部件**及重量
輸出:採用的各部件**,總重量
1,初始化j=-1;
2,k=0;
3,while(k>=0)
3.1result[k]++;
3.2若仍有可選**商且無法滿足約束條件【總**不大於d】,則對下一**商的判斷;
3.3若result[k]=m即該部件已無可選**商,則回溯,result[k]=-1,k–即重置當前部件的**商結果,回溯至上一節點的選擇。
4,輸出結果。
c++實現
#includeusing namespace std;
int n, m; int d;
int weight[10][10];
int value[10][10];
int *result = new int[n];
int check(int i)
int main()
for (int i = 0; i < n; i++)
for (int a = 0; a < n; a++)
result[a] = -1;
int k = 0; int temp = 99999; int *r = new int[n];
//k表示正在探索適合部件的編號
while (k >= 0)
} //有可選**商進行下一部件的判斷
if (result[k] < m&&k < n - 1)
for (int a = 0; a < n; a++)
cout << "\n";
cout << temp;
return 0;
}
演算法之回溯法
回溯法非常適合由多個步驟組成的問題,並且每個步驟都有多個選項。當我們在某一步選擇了其中乙個選項時,就進入下一步,然後面臨新選項,重複選擇,直至最終狀態。經典面試題1 矩陣中的路徑 詳見 劍指offer 面試題12 易錯點 1.由於路徑不能重複進入矩陣的格仔,因此還需定義和字元矩陣大小一樣的布林值矩陣...
常用演算法之回溯法
回溯演算法實際上乙個類似列舉的搜尋嘗試過程,主要是在搜尋嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就 回溯 返回,嘗試別的路徑。回溯法是一種選優搜尋法,按選優條件向前搜尋,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法,...
經典演算法之回溯法
1 綜述 回溯法可以看成是蠻力法的公升級版,它從解決問題每一步的所有可能選項裡系統的選擇出乙個可行的解決方案。回溯法非常適合由多個步驟組成的問題,並且每個步驟都有多個選項。當我們在某一步選擇了其中乙個選項時,就進入下一步,然後面臨新的選項。我們就這麼重複選擇,直至到達最終的狀態。用回溯法解決的問題的...