1. 程式人生 > >動態規劃 剪繩子 (JS 實現)

動態規劃 剪繩子 (JS 實現)

題目

現有一根長度為N的繩子,需要你剪成M段,使M段的乘積最大。(其中M、N都為整數,剪成的每段長度也為整數,N已知,M未知)。例如長度為8的繩子,當剪為3段乘積最大,即2*3*3=18.

思路

看到這種求最優解的題型,你就應該思考一下動態規劃是否適合。這個繩子我可以一次一次的剪,第一次剪成兩段,這就變成兩根新繩子,只要我分別知道這兩根新繩子最大的乘積,那麼我就知道了整條繩子的最大乘積了,這就將一個問題,劃分為兩個子問題了,且各子問題之間相互獨立,滿足最優子結構,因此可以使用動態規劃

首先確定邊界條件和狀態轉移方程:

  • 當繩子長度為1時,最大乘積為0
  • 當繩子長度為2時,可以剪成1*1,最大乘積為1
  • 當繩子長度為3時,可以剪成(1*2,1*1*1),最大乘積為2
  • 當繩子長度為4時,可以剪成(1*1*1*1, 1*2*1, 2*2, 1*3),最大乘積為4
  • 當繩子長度為5時,可以剪成(1*1*1*1*1, 1*2*2, 3*2, 1*2*1*1, 1*3*1,1*4),最大乘積為6

我們可以看到,當繩子長度n大於等於4時,f(n) = max( f(i) * f(n-i) ),其中1 < i <= [n/2],因此我們可以用遍歷來實現狀態轉移方程

程式碼

function LineMax(n){
    if (n<=1) return 0;
    if (n==2
) return 1; if (n==3) return 2; const a =[0,1,2,3]; //排出前面的邊界條件,第i項表示長度為i的繩子的最大乘積 const b =[[0],[1],[2],[3]]; //第i項表示,長度為i繩子的最大乘積組合 for (var i=4;i<=n;i++){ a[i] = 0; //初始化 for (var j=1;j<= n/2;j++){ //迴圈找出最大乘積及組合並分別記錄在a,b陣列中 if (a[j]*a[i-j] >a[i]){ a[i] = a[j]*a[i-j]; b[i] = [...b[j], ...b[i-j]]; } } } console.log(a[n]); //輸出長度為n的繩子最大乘積
console.log(b[n]); //輸出長度為n的繩子最大乘積時的劃分組合 }