前端學習演算法1 :老虎和羊,吃不吃問題(動態規劃入門)

Ace7523發表於2019-02-07

前端學習演算法1 :老虎和羊,吃不吃問題(動態規劃入門)

撇開什麼是動態規劃不談,我們先來看看題幹:

有500只老虎,1只羊,一片草原。老虎和羊,都可以吃草活著,對,這個題中的老虎可以吃草。老虎呢,也能吃羊,不允許很多隻老虎一起吃羊,只允許一隻老虎吃一隻羊,並且,吃完羊之後,這個老虎就會變成羊。那麼問,老虎會不會吃羊? 提示:老虎很聰明,每隻老虎都很聰明。

小A回答

不吃啊,我堂堂威風老虎,幹嘛要變成羊?並且變成羊之後,就該被欺負了

老師說

你坐下

小B回答

吃,因為羊肉好吃

老師說

你坐下

小C回答

不吃,羊那麼可愛,吃了幹嘛,不吃還能多個小夥伴

小M回答

不吃! 要保護生態平衡!

老師說

這題我能不能撤回?

不開玩笑了,答案在下面揭曉,為了不使得一開啟頁面就看到答案,我加些空格。

10

9

8

7

6

5

4

3

2

1

公佈答案:不吃。為什麼呢?因為老虎很聰明啊。WTF,這是什麼理由?不急不急,看看下面的解釋,(先插播一個廣告,就是本人非常喜歡的遊戲‘逆轉裁判’,文字遊戲,結局通常是大逆轉,太贊。)

無從下手之際,不妨逆轉一下思維,直接想500這個數字,怎麼也不具有什麼代表性,要是能聯想起大學時候的數學歸納法,就好辦多了。數學歸納法通常用來證明一些看起來就不用證明的東西,無從下手的時候,就找特殊情況,比如無窮小的時候滿足,無窮大的時候滿足,然後再證明個有代表性的一般特例滿足就好了。

那麼我們也從特殊情況入手

  1. 現在只有 1 老虎,1 羊,那麼這隻羊會被吃嗎?

肯定被吃了,老虎吃了羊後,變成羊,也不會有生命危險了。老虎很聰明,幹嘛不吃。

  1. 現在只有 2 老虎,1 羊,那麼這隻羊會被吃嗎?

不會吃。這兩隻老虎都很聰明,吃了後自己變成了羊,就會被另一隻老虎吃掉自己。

  1. 現在只有 3 老虎,1 羊,那麼這隻羊會被吃嗎?

吃啊,吃! 反正吃完後,變成上面的情況後沒有老虎敢吃我了,我得體驗體驗羊肉。

  1. 現在只有 4 老虎,1 羊,那麼這隻羊會被吃嗎?

不吃,吃了後變成上面情況後,自己變成了羊,該被吃掉了。

  1. 現在只有 5 老虎,1 羊,那麼這隻羊會被吃嗎?

吃啊,吃! 反正吃完後,變成上面的情況後沒有老虎敢吃我了,我得體驗體驗羊肉。

  1. 現在只有 6 老虎,1 羊,那麼這隻羊會被吃嗎?

不吃,吃了後變成上面情況後,自己變成了羊,該被吃掉了。

那麼由以上的情況推導一下,是不是規律已經出來了? 前提不是說了嗎,每個老虎都很聰明,500是什麼數?是偶數,那麼是不會吃的。

動態規劃 Dynamic Programming

動態規劃意思就是說,大事化小,小事化了。術語的話,包含三個,最優子結構邊界狀態轉移公式,舉一個最簡單的例子,能更好的理解這三個術語

樓梯臺階有12階,一步只能走1階或者2階,那麼,請問走完樓梯有多少走法?

  1. 走到最後一個臺階的前一個情況,只能有兩種吧,就是從第11臺階走一步上來,或者從10臺階走兩步上來,那麼不管有多少走法走到了11階假設是X種走法吧,假設是Y種走法走到了10階,那麼,走到12階的走法一定是X+Y,這個是成立的吧。這就是最優子結構
  2. 那什麼是邊界呢?本例子中,走到第一個臺階,就一種走法吧,沒有臺階,那就0種走法吧,走到第二個臺階,也就2種走法,其實這就是邊界了。
  3. 那麼狀態轉移公式就水到渠成了,F(n) = F(n-1) + F(n-2)

別說話,看程式碼

function fun(n) {
  if (n < 0){
	return 0
  }
  if (n === 1){
	return 1
  }
  if (n === 2){
	return 2
  }
  return fun(n-1) + fun(n-2)
}
console.log('12臺階的走法 :' + fun(12) )
console.log('11臺階的走法 :' + fun(11) )
console.log('10臺階的走法 :' + fun(10) )
console.log('9臺階的走法 :' + fun(9) )
console.log('8臺階的走法 :' + fun(8) )
console.log('7臺階的走法 :' + fun(7) )
console.log('6臺階的走法 :' + fun(6) )
console.log('5臺階的走法 :' + fun(5) )
console.log('4臺階的走法 :' + fun(4) )
console.log('3臺階的走法 :' + fun(3) )
console.log('2臺階的走法 :' + fun(2) )
console.log('1臺階的走法 :' + fun(1) )
複製程式碼

執行結果如下

前端學習演算法1 :老虎和羊,吃不吃問題(動態規劃入門)

其實上面程式碼是存在問題的,有很多重複的計算。不妨把n限定小一些來看 f(4) = f(3) + f(2),而f(3) = f(2) + f(1),f(2)就是重複計算了。那麼程式碼如何進行優化一翻?

看到上面列印的結果,其實也能發現出規律來,就是3的結果,只依賴1和2,那4的結果有隻依賴2和3,而1,2的結果又是顯而易見的,那麼我們可否逆轉一下思維,從下而上計算呢?於是程式碼如下改造,也就是真正的動態規劃實現

function fun(n) {
  if (n < 0){
	return 0
  }
  if (n === 1){
	return 1
  }
  if (n === 2){
	return 2
  }
  var a = 1
  var b = 2
  var temp = 0
  for(var i = 3; i <= n; i++){
	temp = a + b
	a=b
	b=temp
  }
  return temp
}
console.log( '優化版' )
console.log('12臺階的走法 :' + fun(12) )
console.log('11臺階的走法 :' + fun(11) )
console.log('10臺階的走法 :' + fun(10) )
console.log('9臺階的走法 :' + fun(9) )
console.log('8臺階的走法 :' + fun(8) )
console.log('7臺階的走法 :' + fun(7) )
console.log('6臺階的走法 :' + fun(6) )
console.log('5臺階的走法 :' + fun(5) )
console.log('4臺階的走法 :' + fun(4) )
console.log('3臺階的走法 :' + fun(3) )
console.log('2臺階的走法 :' + fun(2) )
console.log('1臺階的走法 :' + fun(1) )
複製程式碼

執行結果和之前的相同,如下

前端學習演算法1 :老虎和羊,吃不吃問題(動態規劃入門)

(其實這也只是動態規劃入門,後續會有進階題目。其實也沒啥人看,只是寫給自己記錄一下而已)

相關文章