前言
算法中有很多會用到歸納的思想,如遞歸等算法的基礎都是歸納。今天來看看歸納的主要思想以及基於歸納的一些算法設計。
歸納
證明當n = 1時命題成立。
證明如果在n = k時命題成立,那麼可以推導出在n = k+1時命題也成立。(m代表任意自然數)
這種方法的原理在於:首先證明在某個起點值時命題成立,然後證明從一個值到下一個值的過程有效。當這兩點都已經證明,那麼任意值都可以通過反覆使用這個方法推導出來。
算法樣例
1、多項式求解
Pn(x) = anxn+an−1xn+…+a1x+a0
求Pn(x)
歸納假設:我們已求解出Pn-1(x) = an−1xn+…+a1x+a0
則Pn(x) = Pn-1(x) + an * x^n
Tn = Tn + n + 1
int P(n){ if(n == 0){ return a[0]; } else{ P(n) = P(n - 1) + a[n] * x ^ n; } }
增強歸納
同時歸納P(n)與x的n次方
int x[n] int P(n){ if(n == 0){ return a[0]; } else{ x[n] = x[n - 1] * x; P(n) = P(n - 1) + a[n] * x[n]; } }
Tn = Tn-1 + 3
2n次乘法,n次加法
優化
Pn-1(x) = anxn −1+an−1xn+…+a1x
Pn(x) = P(n) * x + a[N - n]
Tn = Tn- 1 + 2
N 次乘法,n次加法
int P(n){ if(n == 0){ return a[0]; } else{ P(n) = x * P(n - 1) + a[N - n]; } }
2. 最大導出子圖
找G的最大導出子圖H, H 中所有頂點的度大於或等於k
歸納假設
頂點數少於n的,我們可以找到它的導出子圖
對於n的圖
遍歷所有點
若全都度>= k 則其就是最大的導出子圖
若有點小於k,刪去該點及所連邊,檢查剩下的圖
剩下的圖邊數少於n,根據歸納假設,可求得最大導出子圖
Graph(n){ flag = 1; if(n = k){ there is no biggest induced subgraph } for(every v in G){ if(deg(v) < k){ flag = 0; break; } } if(flag == 0){ Graph(n - 1); } else{ Graph is the biggest induced subgraph } }
3. 一對一映射
集合A, f爲A到A的映射,A中找子集S使f在S上是one-to-one function
歸納假設
假設n-1規模的集合我們可以找到相應的S
對於n
遍歷所有元素
若每個元素都被映射到
則f爲one-to-one的
A便是S
若有元素沒有被映射到
則S中一定沒有這個元素
刪去這個元素
剩下n-1個,根據歸納
可求解
c[N] = {0, 0, ... } //The in degree of element i one_to_ont(){ queue for(i = 0; i < n; i++){ c[f(i)]++; } for(i = 0; i < n; i++){ if(c[i] = 0){ enque(i); } } while(!queue.empty()){ v = dequeue(); G = G - v; c[f(i)]--; if(c[f(i)] == 0){ enque(f(i)); } } }
4. 社會名流
人與人關係有知道與不知道,若一個人被所有人知道,但自己不知道其他所有人,則他是社會名流。
歸納假設:
n-1規模的人中可以求解社會名流問題
隨便拿兩個人A和B
問A是否知道B
若知道,則A一定不是社會名流,刪除
若不知道,則B一點不是社會名流,刪除
還剩n-1個人
根據歸納假設,可以求解
不斷刪去,最後剩下的人有可能是,也可能不是
就是個社會名流的candidate
讓他與其他所有人每個問兩個問題,就可以確定其是不是
O(3(n-1))
know[i][j] // i know j socialStar(){ i = 1; j = 2; next = 3; for(k = 0; k < n - 1; k++){ if(know[i][j]){ i = next; } else{ j = next; } next++; } if(i == next + 1){ candidate = j } else{ candidate = i; } for(i = 0; i < n; i++){ check know[candidate][i] check know[i][candidate] } }
5. 計算平衡因子
計算一棵樹(n個節點)上所有節點的平衡因子
歸納假設:已知節點數<n的樹上所有節點的平衡因子
發現這個歸納沒法求n
增強的歸納假設:已知節點數<n的樹上每個節點的平衡因子和高度
對於n個節點的樹
知道其根節點的左子樹與右子樹
根據歸納假設
知道左子樹高度
知道右子樹高度
可以求根的平衡因子
6. 最大連續子序列
給定序列 x1, x2, x3 … xn
求和最大的連續的子序列
歸納假設:已知規模<n的序列 的最大子序列
加入xn,沒法推得規模n的序列的最大子序列
增強的歸納假設:已知的規模<n的序列的最大子序列與後綴最大的子序列
加入xn
若xn加入使後綴序列和大於原先的最大子序列
則新序列最大後綴子序列加入xn,且最大子序列爲最大後綴子序列
若xn加入使後綴序列和還是小於原先的最大子序列,但>0
則新序列最大後綴子序列加入xn,且最大子序列仍爲原來的
若xn加入使後綴序列和<0
則新序列最大後綴子序列爲0,且最大子序列仍爲原來的
進化
A[i]爲以第i個元素結尾的最大子序列的和
I -> I + 1
若A[i] > 0, 則A[I + 1] = x[I + 1] + A[i]
Xi 加入其中
若A[i] < 0, 則A[I + 1] = x[I + 1]
最後遍歷A[i], 求最大值
總結
只要一個問題有基礎解,並能由更小的問題構造出來,那麼這個問題就可以用歸納來解決。基於歸納的算法還有很多很多,主要是明白了這種歸納的思想,然後就可以使用函數遞歸實現了。