當前層的須要使用下一層調用的結果,並且,各個層的調用之間知足必定的規律。
【怎麼更好地終極理解遞歸算法】html
遞歸算法的實現得以依賴於棧這種數據結構,棧的存在使得各層調用中的現場保護與恢復不須要人爲干預。node
遞歸算法的關鍵:【如何去理解遞歸,想到遞歸,運用遞歸】ios
例一:求1到100的和。算法
#include <stdio.h> int sum(int x) { if(x == 1) //基線條件 { return 1; } return sum(x-1) + x; //遞歸條件 } int main() { int ret = 0; ret = sum(100); printf("%d", ret); return 0; }
用一個公式表達以下:網絡
\[ sum(100) = 100 + sum(99) = 100 + 99 + sum(98) = ... = 100 + 99 + ... + 2 + sum(1) \]數據結構
計算機求解時,將\(sum(x)\)(\(x\)從100到2)依次壓入到棧中,直到\(x=1\)時,程序能夠計算出\(sum(1) = 1\),彈出\(sum(1)\),而後將\(sum(1)\)的計算結果返回用於計算\(sum(2)\),當計算出\(sum(2)\)後,返回結果,彈出\(sum(2)\),...,最終,直到計算出\(sum(100)\),彈出\(sum(100)\),棧空結束。函數
例二:藍橋杯: 六角填數spa
對於該問題,咱們使用遞歸算法是在不斷地向空白位置填充數字,明確目的後,咱們也肯定了遞歸條件。.net
#include <iostream> using namespace std; int pos[13] = {0}; int vis[13] = {0}; int line[6] = {0}; void dfs(int node) { if(node == 1 || node == 2 || node == 12) //若是當前節點是三個網絡初始化時的任意一個節點 { dfs(node+1); //遞歸條件:跳過當前節點,訪問下一個節點 return; } else //若是當前節點沒有被訪問,則對當前節點進行賦值 { if(node <= 12) { for(int num = 1; num < 13; num++) //遍歷12個數字 { if(vis[num] == 0) //若是該數字沒有被使用過 { vis[num] = 1; //如今使用這個數字 pos[node] = num; //把如今這個數字賦值給當前訪問的結點 dfs(node+1); //遞歸條件:給下一個點賦值(若是正常狀況知足,不會進入到下一行) //【重點理解】若是對全部節點都賦值後仍不知足題意,清除當前數字的標誌, // 令其在下一次仍然能夠使用該數字。 vis[num] = 0; } } } else //已經對12個節點都進行了賦值,判斷當前網絡是否知足題意 { line[0] = pos[1] + pos[3] + pos[6] + pos[8]; line[1] = pos[1] + pos[4] + pos[7] + pos[11]; line[2] = pos[8] + pos[9] + pos[10] + pos[11]; line[3] = pos[2] + pos[3] + pos[4] + pos[5]; line[4] = pos[2] + pos[6] + pos[9] + pos[12]; line[5] = pos[5] + pos[7] + pos[10] + pos[12]; if(line[0] == line[1] && line[1] == line[2] && line[2] == line[3] && line[3] == line[4] && line[4] == line[5]) {// 基線條件:若是知足題意,打印結果 cout << "pos[6] = " << pos[6] << endl; return; } else {// 基線條件:若是不知足題意,結束本次函數 return; } } } } int main() { //初始化網絡參數 pos[1] = 1; vis[1] = 1; pos[2] = 8; vis[8] = 1; pos[12]= 3; vis[3] = 1; dfs(1); //深度優先搜索算法 return 0; }
對於該問題的理解,能夠參考【轉載】深度優先搜索算法。3d